src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SALauncher.java
branchdatagramsocketimpl-branch
changeset 58678 9cf78a70fa4f
parent 55073 f4702c8c9b3f
child 58679 9c3209ff7550
equal deleted inserted replaced
58677:13588c901957 58678:9cf78a70fa4f
    24 
    24 
    25 package sun.jvm.hotspot;
    25 package sun.jvm.hotspot;
    26 
    26 
    27 import java.util.ArrayList;
    27 import java.util.ArrayList;
    28 import java.util.Arrays;
    28 import java.util.Arrays;
       
    29 import java.util.ArrayList;
       
    30 import java.util.HashMap;
       
    31 import java.util.List;
       
    32 import java.util.Map;
       
    33 import java.util.function.Consumer;
    29 
    34 
    30 import sun.jvm.hotspot.tools.JStack;
    35 import sun.jvm.hotspot.tools.JStack;
    31 import sun.jvm.hotspot.tools.JMap;
    36 import sun.jvm.hotspot.tools.JMap;
    32 import sun.jvm.hotspot.tools.JInfo;
    37 import sun.jvm.hotspot.tools.JInfo;
    33 import sun.jvm.hotspot.tools.JSnap;
    38 import sun.jvm.hotspot.tools.JSnap;
    44         System.out.println("    jsnap  --help\tto get more information");
    49         System.out.println("    jsnap  --help\tto get more information");
    45         return false;
    50         return false;
    46     }
    51     }
    47 
    52 
    48     private static boolean commonHelp(String mode) {
    53     private static boolean commonHelp(String mode) {
       
    54         return commonHelp(mode, false);
       
    55     }
       
    56 
       
    57     private static boolean commonHelpWithConnect(String mode) {
       
    58         return commonHelp(mode, true);
       
    59     }
       
    60 
       
    61     private static boolean commonHelp(String mode, boolean canConnectToRemote) {
    49         // --pid <pid>
    62         // --pid <pid>
    50         // --exe <exe>
    63         // --exe <exe>
    51         // --core <core>
    64         // --core <core>
    52         System.out.println("    --pid <pid>      \tTo attach to and operate on the given live process.");
    65         // --connect [<id>@]<host>
    53         System.out.println("    --core <corefile>\tTo operate on the given core file.");
    66         System.out.println("    --pid <pid>             To attach to and operate on the given live process.");
       
    67         System.out.println("    --core <corefile>       To operate on the given core file.");
    54         System.out.println("    --exe <executable for corefile>");
    68         System.out.println("    --exe <executable for corefile>");
       
    69         if (canConnectToRemote) {
       
    70             System.out.println("    --connect [<id>@]<host> To connect to a remote debug server (debugd).");
       
    71         }
    55         System.out.println();
    72         System.out.println();
    56         System.out.println("    The --core and --exe options must be set together to give the core");
    73         System.out.println("    The --core and --exe options must be set together to give the core");
    57         System.out.println("    file, and associated executable, to operate on. Otherwise the --pid");
    74         System.out.println("    file, and associated executable, to operate on. They can use");
    58         System.out.println("    option can be set to operate on a live process.");
    75         System.out.println("    absolute or relative paths.");
    59         System.out.println("    The arguments for --exe and --core can use absolute or relative paths.");
    76         System.out.println("    The --pid option can be set to operate on a live process.");
       
    77         if (canConnectToRemote) {
       
    78             System.out.println("    The --connect option can be set to connect to a debug server (debugd).");
       
    79             System.out.println("    --core, --pid, and --connect are mutually exclusive.");
       
    80         } else {
       
    81             System.out.println("    --core and --pid are mutually exclusive.");
       
    82         }
    60         System.out.println();
    83         System.out.println();
    61         System.out.println("    Examples: jhsdb " + mode + " --pid 1234");
    84         System.out.println("    Examples: jhsdb " + mode + " --pid 1234");
    62         System.out.println("          or  jhsdb " + mode + " --core ./core.1234 --exe ./myexe");
    85         System.out.println("          or  jhsdb " + mode + " --core ./core.1234 --exe ./myexe");
       
    86         if (canConnectToRemote) {
       
    87             System.out.println("          or  jhsdb " + mode + " --connect debugserver");
       
    88             System.out.println("          or  jhsdb " + mode + " --connect id@debugserver");
       
    89         }
    63         return false;
    90         return false;
    64     }
    91     }
    65 
    92 
    66     private static boolean debugdHelp() {
    93     private static boolean debugdHelp() {
    67         // [options] <pid> [server-id]
    94         // [options] <pid> [server-id]
    68         // [options] <executable> <core> [server-id]
    95         // [options] <executable> <core> [server-id]
    69         System.out.println("    --serverid <id>  \tA unique identifier for this debug server.");
    96         System.out.println("    --serverid <id>         A unique identifier for this debug server.");
    70         return commonHelp("debugd");
    97         return commonHelp("debugd");
    71     }
    98     }
    72 
    99 
    73     private static boolean jinfoHelp() {
   100     private static boolean jinfoHelp() {
    74         // --flags -> -flags
   101         // --flags -> -flags
    75         // --sysprops -> -sysprops
   102         // --sysprops -> -sysprops
    76         System.out.println("    --flags          \tTo print VM flags.");
   103         System.out.println("    --flags                 To print VM flags.");
    77         System.out.println("    --sysprops       \tTo print Java System properties.");
   104         System.out.println("    --sysprops              To print Java System properties.");
    78         System.out.println("    <no option>      \tTo print both of the above.");
   105         System.out.println("    <no option>             To print both of the above.");
    79         return commonHelp("jinfo");
   106         return commonHelpWithConnect("jinfo");
    80     }
   107     }
    81 
   108 
    82     private static boolean jmapHelp() {
   109     private static boolean jmapHelp() {
    83         // --heap -> -heap
   110         // --heap -> -heap
    84         // --binaryheap -> -heap:format=b
   111         // --binaryheap -> -heap:format=b
    85         // --histo -> -histo
   112         // --histo -> -histo
    86         // --clstats -> -clstats
   113         // --clstats -> -clstats
    87         // --finalizerinfo -> -finalizerinfo
   114         // --finalizerinfo -> -finalizerinfo
    88 
   115 
    89         System.out.println("    <no option>      \tTo print same info as Solaris pmap.");
   116         System.out.println("    <no option>             To print same info as Solaris pmap.");
    90         System.out.println("    --heap           \tTo print java heap summary.");
   117         System.out.println("    --heap                  To print java heap summary.");
    91         System.out.println("    --binaryheap     \tTo dump java heap in hprof binary format.");
   118         System.out.println("    --binaryheap            To dump java heap in hprof binary format.");
    92         System.out.println("    --dumpfile <name>\tThe name of the dump file.");
   119         System.out.println("    --dumpfile <name>       The name of the dump file.");
    93         System.out.println("    --histo          \tTo print histogram of java object heap.");
   120         System.out.println("    --histo                 To print histogram of java object heap.");
    94         System.out.println("    --clstats        \tTo print class loader statistics.");
   121         System.out.println("    --clstats               To print class loader statistics.");
    95         System.out.println("    --finalizerinfo  \tTo print information on objects awaiting finalization.");
   122         System.out.println("    --finalizerinfo         To print information on objects awaiting finalization.");
    96         return commonHelp("jmap");
   123         return commonHelpWithConnect("jmap");
    97     }
   124     }
    98 
   125 
    99     private static boolean jstackHelp() {
   126     private static boolean jstackHelp() {
   100         // --locks -> -l
   127         // --locks -> -l
   101         // --mixed -> -m
   128         // --mixed -> -m
   102         System.out.println("    --locks          \tTo print java.util.concurrent locks.");
   129         System.out.println("    --locks                 To print java.util.concurrent locks.");
   103         System.out.println("    --mixed          \tTo print both Java and native frames (mixed mode).");
   130         System.out.println("    --mixed                 To print both Java and native frames (mixed mode).");
   104         return commonHelp("jstack");
   131         return commonHelpWithConnect("jstack");
   105     }
   132     }
   106 
   133 
   107     private static boolean jsnapHelp() {
   134     private static boolean jsnapHelp() {
   108         System.out.println("    --all            \tTo print all performance counters.");
   135         System.out.println("    --all                   To print all performance counters.");
   109         return commonHelp("jsnap");
   136         return commonHelpWithConnect("jsnap");
   110     }
   137     }
   111 
   138 
   112     private static boolean toolHelp(String toolName) {
   139     private static boolean toolHelp(String toolName) {
   113         if (toolName.equals("jstack")) {
   140         switch (toolName) {
   114             return jstackHelp();
   141             case "jstack":
   115         }
   142                 return jstackHelp();
   116         if (toolName.equals("jinfo")) {
   143             case "jinfo":
   117             return jinfoHelp();
   144                 return jinfoHelp();
   118         }
   145             case "jmap":
   119         if (toolName.equals("jmap")) {
   146                 return jmapHelp();
   120             return jmapHelp();
   147             case "jsnap":
   121         }
   148                 return jsnapHelp();
   122         if (toolName.equals("jsnap")) {
   149             case "debugd":
   123             return jsnapHelp();
   150                 return debugdHelp();
   124         }
   151             case "hsdb":
   125         if (toolName.equals("debugd")) {
   152             case "clhsdb":
   126             return debugdHelp();
   153                 return commonHelp(toolName);
   127         }
   154             default:
   128         if (toolName.equals("hsdb")) {
   155                 return launcherHelp();
   129             return commonHelp("hsdb");
   156         }
   130         }
   157     }
   131         if (toolName.equals("clhsdb")) {
   158 
   132             return commonHelp("clhsdb");
   159     private static final String NO_REMOTE = null;
   133         }
   160 
   134         return launcherHelp();
   161     private static String[] buildAttachArgs(Map<String, String> newArgMap,
   135     }
   162                                             boolean allowEmpty) {
   136 
   163         String pid = newArgMap.remove("pid");
   137     private static void buildAttachArgs(ArrayList<String> newArgs, String pid,
   164         String exe = newArgMap.remove("exe");
   138                                   String exe, String core, boolean allowEmpty) {
   165         String core = newArgMap.remove("core");
   139         if (!allowEmpty && (pid == null) && (exe == null)) {
   166         String connect = newArgMap.remove("connect");
   140             throw new SAGetoptException("You have to set --pid or --exe.");
   167         if (!allowEmpty && (pid == null) && (exe == null) && (connect == NO_REMOTE)) {
       
   168             throw new SAGetoptException("You have to set --pid or --exe or --connect.");
       
   169         }
       
   170 
       
   171         List<String> newArgs = new ArrayList<>();
       
   172         for (var entry : newArgMap.entrySet()) {
       
   173             newArgs.add(entry.getKey());
       
   174             if (entry.getValue() != null) {
       
   175                 newArgs.add(entry.getValue());
       
   176             }
   141         }
   177         }
   142 
   178 
   143         if (pid != null) { // Attach to live process
   179         if (pid != null) { // Attach to live process
   144             if (exe != null) {
   180             if (exe != null) {
   145                 throw new SAGetoptException("Unnecessary argument: --exe");
   181                 throw new SAGetoptException("Unnecessary argument: --exe");
   146             } else if (core != null) {
   182             } else if (core != null) {
   147                 throw new SAGetoptException("Unnecessary argument: --core");
   183                 throw new SAGetoptException("Unnecessary argument: --core");
       
   184             } else if (connect != NO_REMOTE) {
       
   185                 throw new SAGetoptException("Unnecessary argument: --connect");
   148             } else if (!pid.matches("^\\d+$")) {
   186             } else if (!pid.matches("^\\d+$")) {
   149                 throw new SAGetoptException("Invalid pid: " + pid);
   187                 throw new SAGetoptException("Invalid pid: " + pid);
   150             }
   188             }
   151 
   189 
   152             newArgs.add(pid);
   190             newArgs.add(pid);
   153         } else if (exe != null) {
   191         } else if (exe != null) {
   154             if (exe.length() == 0) {
   192             if (connect != NO_REMOTE) {
       
   193                 throw new SAGetoptException("Unnecessary argument: --connect");
       
   194             } else if (exe.length() == 0) {
   155                 throw new SAGetoptException("You have to set --exe.");
   195                 throw new SAGetoptException("You have to set --exe.");
   156             }
   196             }
   157 
   197 
   158             newArgs.add(exe);
   198             newArgs.add(exe);
   159 
   199 
   160             if ((core == null) || (core.length() == 0)) {
   200             if ((core == null) || (core.length() == 0)) {
   161                 throw new SAGetoptException("You have to set --core.");
   201                 throw new SAGetoptException("You have to set --core.");
   162             }
   202             }
   163 
   203 
   164             newArgs.add(core);
   204             newArgs.add(core);
   165         }
   205         } else if (connect != NO_REMOTE) {
       
   206             newArgs.add(connect);
       
   207         }
       
   208 
       
   209         return newArgs.toArray(new String[0]);
       
   210     }
       
   211 
       
   212     /**
       
   213      * This method converts jhsdb-style options (oldArgs) to old fashioned
       
   214      * style. SALauncher delegates the work to the entry point of each tool.
       
   215      * Thus we need to convert the arguments.
       
   216      * For example, `jhsdb jstack --mixed` needs to be converted to `jstack -m`.
       
   217      *
       
   218      * longOptsMap holds the rule how this method should convert the args.
       
   219      * The key is the name of jhsdb style, the value is the name of
       
   220      * old fashioned style. If you want to convert mixed option in jstack,
       
   221      * you need to set "mixed" to the key, and to set "-m" to the value
       
   222      * in longOptsMap. If the option have the value, you need to add "=" to
       
   223      * the key like "exe=".
       
   224      *
       
   225      * You also can set the options which cannot be mapped to old fashioned
       
   226      * arguments. For example, `jhsdb jmap --binaryheap` cannot be mapped to
       
   227      * `jmap` option directly. But you set it to longOptsMap, then you can know
       
   228      * the user sets "binaryheap" option, and SALauncher should set
       
   229      * "-heap:format:b" to jmap option.
       
   230      *
       
   231      * This method returns the map of the old fashioned key/val pairs.
       
   232      * It can be used to build args in string array at buildAttachArgs().
       
   233      */
       
   234     private static Map<String, String> parseOptions(String[] oldArgs,
       
   235                                                     Map<String, String> longOptsMap) {
       
   236         SAGetopt sg = new SAGetopt(oldArgs);
       
   237         String[] longOpts = longOptsMap.keySet().toArray(new String[0]);
       
   238         Map<String, String> newArgMap = new HashMap<>();
       
   239 
       
   240         /*
       
   241          * Parse each jhsdb-style option via SAGetopt.
       
   242          * SAGetopt parses and validates the argument. If the user passes invalid
       
   243          * option, SAGetoptException will be occurred at SAGetopt::next.
       
   244          * Thus there is no need to validate it here.
       
   245          *
       
   246          * We can get option value via SAGetopt::get. If jhsdb-style option has
       
   247          * '=' at the tail, we put old fashioned option with it to newArgMap.
       
   248          */
       
   249         String s;
       
   250         while ((s = sg.next(null, longOpts)) != null) {
       
   251             var val = longOptsMap.get(s);
       
   252             if (val != null) {
       
   253                 newArgMap.put(val, null);
       
   254             } else {
       
   255                 val = longOptsMap.get(s + "=");
       
   256                 if (val != null) {
       
   257                     newArgMap.put(val, sg.getOptarg());
       
   258                 }
       
   259             }
       
   260         }
       
   261 
       
   262         return newArgMap;
   166     }
   263     }
   167 
   264 
   168     private static void runCLHSDB(String[] oldArgs) {
   265     private static void runCLHSDB(String[] oldArgs) {
   169         SAGetopt sg = new SAGetopt(oldArgs);
   266         Map<String, String> longOptsMap = Map.of("exe=", "exe",
   170         String[] longOpts = {"exe=", "core=", "pid="};
   267                                                  "core=", "core",
   171 
   268                                                  "pid=", "pid");
   172         ArrayList<String> newArgs = new ArrayList();
   269         Map<String, String> newArgMap = parseOptions(oldArgs, longOptsMap);
   173         String pid = null;
   270         CLHSDB.main(buildAttachArgs(newArgMap, true));
   174         String exe = null;
       
   175         String core = null;
       
   176         String s = null;
       
   177 
       
   178         while((s = sg.next(null, longOpts)) != null) {
       
   179             if (s.equals("exe")) {
       
   180                 exe = sg.getOptarg();
       
   181                 continue;
       
   182             }
       
   183             if (s.equals("core")) {
       
   184                 core = sg.getOptarg();
       
   185                 continue;
       
   186             }
       
   187             if (s.equals("pid")) {
       
   188                 pid = sg.getOptarg();
       
   189                 continue;
       
   190             }
       
   191         }
       
   192 
       
   193         buildAttachArgs(newArgs, pid, exe, core, true);
       
   194         CLHSDB.main(newArgs.toArray(new String[newArgs.size()]));
       
   195     }
   271     }
   196 
   272 
   197     private static void runHSDB(String[] oldArgs) {
   273     private static void runHSDB(String[] oldArgs) {
   198         SAGetopt sg = new SAGetopt(oldArgs);
   274         Map<String, String> longOptsMap = Map.of("exe=", "exe",
   199         String[] longOpts = {"exe=", "core=", "pid="};
   275                                                  "core=", "core",
   200 
   276                                                  "pid=", "pid");
   201         ArrayList<String> newArgs = new ArrayList();
   277         Map<String, String> newArgMap = parseOptions(oldArgs, longOptsMap);
   202         String pid = null;
   278         HSDB.main(buildAttachArgs(newArgMap, true));
   203         String exe = null;
       
   204         String core = null;
       
   205         String s = null;
       
   206 
       
   207         while((s = sg.next(null, longOpts)) != null) {
       
   208             if (s.equals("exe")) {
       
   209                 exe = sg.getOptarg();
       
   210                 continue;
       
   211             }
       
   212             if (s.equals("core")) {
       
   213                 core = sg.getOptarg();
       
   214                 continue;
       
   215             }
       
   216             if (s.equals("pid")) {
       
   217                 pid = sg.getOptarg();
       
   218                 continue;
       
   219             }
       
   220         }
       
   221 
       
   222         buildAttachArgs(newArgs, pid, exe, core, true);
       
   223         HSDB.main(newArgs.toArray(new String[newArgs.size()]));
       
   224     }
   279     }
   225 
   280 
   226     private static void runJSTACK(String[] oldArgs) {
   281     private static void runJSTACK(String[] oldArgs) {
   227         SAGetopt sg = new SAGetopt(oldArgs);
   282         Map<String, String> longOptsMap = Map.of("exe=", "exe",
   228         String[] longOpts = {"exe=", "core=", "pid=",
   283                                                  "core=", "core",
   229                                  "mixed", "locks"};
   284                                                  "pid=", "pid",
   230 
   285                                                  "connect=", "connect",
   231         ArrayList<String> newArgs = new ArrayList();
   286                                                  "mixed", "-m",
   232         String pid = null;
   287                                                  "locks", "-l");
   233         String exe = null;
   288         Map<String, String> newArgMap = parseOptions(oldArgs, longOptsMap);
   234         String core = null;
       
   235         String s = null;
       
   236 
       
   237         while((s = sg.next(null, longOpts)) != null) {
       
   238             if (s.equals("exe")) {
       
   239                 exe = sg.getOptarg();
       
   240                 continue;
       
   241             }
       
   242             if (s.equals("core")) {
       
   243                 core = sg.getOptarg();
       
   244                 continue;
       
   245             }
       
   246             if (s.equals("pid")) {
       
   247                 pid = sg.getOptarg();
       
   248                 continue;
       
   249             }
       
   250             if (s.equals("mixed")) {
       
   251                 newArgs.add("-m");
       
   252                 continue;
       
   253             }
       
   254             if (s.equals("locks")) {
       
   255                 newArgs.add("-l");
       
   256                 continue;
       
   257             }
       
   258         }
       
   259 
       
   260         buildAttachArgs(newArgs, pid, exe, core, false);
       
   261         JStack jstack = new JStack(false, false);
   289         JStack jstack = new JStack(false, false);
   262         jstack.runWithArgs(newArgs.toArray(new String[newArgs.size()]));
   290         jstack.runWithArgs(buildAttachArgs(newArgMap, false));
   263     }
   291     }
   264 
   292 
   265     private static void runJMAP(String[] oldArgs) {
   293     private static void runJMAP(String[] oldArgs) {
   266         SAGetopt sg = new SAGetopt(oldArgs);
   294         Map<String, String> longOptsMap = Map.of("exe=", "exe",
   267         String[] longOpts = {"exe=", "core=", "pid=",
   295                                                  "core=", "core",
   268               "heap", "binaryheap", "dumpfile=", "histo", "clstats", "finalizerinfo"};
   296                                                  "pid=", "pid",
   269 
   297                                                  "connect=", "connect",
   270         ArrayList<String> newArgs = new ArrayList();
   298                                                  "heap", "-heap",
   271         String pid = null;
   299                                                  "binaryheap", "binaryheap",
   272         String exe = null;
   300                                                  "dumpfile=", "dumpfile",
   273         String core = null;
   301                                                  "histo", "-histo",
   274         String s = null;
   302                                                  "clstats", "-clstats",
   275         String dumpfile = null;
   303                                                  "finalizerinfo", "-finalizerinfo");
   276         boolean requestHeapdump = false;
   304         Map<String, String> newArgMap = parseOptions(oldArgs, longOptsMap);
   277 
   305 
   278         while((s = sg.next(null, longOpts)) != null) {
   306         boolean requestHeapdump = newArgMap.containsKey("binaryheap");
   279             if (s.equals("exe")) {
   307         String dumpfile = newArgMap.get("dumpfile");
   280                 exe = sg.getOptarg();
       
   281                 continue;
       
   282             }
       
   283             if (s.equals("core")) {
       
   284                 core = sg.getOptarg();
       
   285                 continue;
       
   286             }
       
   287             if (s.equals("pid")) {
       
   288                 pid = sg.getOptarg();
       
   289                 continue;
       
   290             }
       
   291             if (s.equals("heap")) {
       
   292                 newArgs.add("-heap");
       
   293                 continue;
       
   294             }
       
   295             if (s.equals("binaryheap")) {
       
   296                 requestHeapdump = true;
       
   297                 continue;
       
   298             }
       
   299             if (s.equals("dumpfile")) {
       
   300                 dumpfile = sg.getOptarg();
       
   301                 continue;
       
   302             }
       
   303             if (s.equals("histo")) {
       
   304                 newArgs.add("-histo");
       
   305                 continue;
       
   306             }
       
   307             if (s.equals("clstats")) {
       
   308                 newArgs.add("-clstats");
       
   309                 continue;
       
   310             }
       
   311             if (s.equals("finalizerinfo")) {
       
   312                 newArgs.add("-finalizerinfo");
       
   313                 continue;
       
   314             }
       
   315         }
       
   316 
       
   317         if (!requestHeapdump && (dumpfile != null)) {
   308         if (!requestHeapdump && (dumpfile != null)) {
   318             throw new IllegalArgumentException("Unexpected argument dumpfile");
   309             throw new IllegalArgumentException("Unexpected argument: dumpfile");
   319         }
   310         }
   320         if (requestHeapdump) {
   311         if (requestHeapdump) {
   321             if (dumpfile == null) {
   312             if (dumpfile == null) {
   322                 newArgs.add("-heap:format=b");
   313                 newArgMap.put("-heap:format=b", null);
   323             } else {
   314             } else {
   324                 newArgs.add("-heap:format=b,file=" + dumpfile);
   315                 newArgMap.put("-heap:format=b,file=" + dumpfile, null);
   325             }
   316             }
   326         }
   317         }
   327 
   318 
   328         buildAttachArgs(newArgs, pid, exe, core, false);
   319         newArgMap.remove("binaryheap");
   329         JMap.main(newArgs.toArray(new String[newArgs.size()]));
   320         newArgMap.remove("dumpfile");
       
   321         JMap.main(buildAttachArgs(newArgMap, false));
   330     }
   322     }
   331 
   323 
   332     private static void runJINFO(String[] oldArgs) {
   324     private static void runJINFO(String[] oldArgs) {
   333         SAGetopt sg = new SAGetopt(oldArgs);
   325         Map<String, String> longOptsMap = Map.of("exe=", "exe",
   334         String[] longOpts = {"exe=", "core=", "pid=",
   326                                                  "core=", "core",
   335                                      "flags", "sysprops"};
   327                                                  "pid=", "pid",
   336 
   328                                                  "connect=", "connect",
   337         ArrayList<String> newArgs = new ArrayList();
   329                                                  "flags", "-flags",
   338         String exe = null;
   330                                                  "sysprops", "-sysprops");
   339         String pid = null;
   331         Map<String, String> newArgMap = parseOptions(oldArgs, longOptsMap);
   340         String core = null;
   332         JInfo.main(buildAttachArgs(newArgMap, false));
   341         String s = null;
       
   342 
       
   343         while((s = sg.next(null, longOpts)) != null) {
       
   344             if (s.equals("exe")) {
       
   345                 exe = sg.getOptarg();
       
   346                 continue;
       
   347             }
       
   348             if (s.equals("core")) {
       
   349                 core = sg.getOptarg();
       
   350                 continue;
       
   351             }
       
   352             if (s.equals("pid")) {
       
   353                 pid = sg.getOptarg();
       
   354                 continue;
       
   355             }
       
   356             if (s.equals("flags")) {
       
   357                 newArgs.add("-flags");
       
   358                 continue;
       
   359             }
       
   360             if (s.equals("sysprops")) {
       
   361                 newArgs.add("-sysprops");
       
   362                 continue;
       
   363             }
       
   364         }
       
   365 
       
   366         buildAttachArgs(newArgs, pid, exe, core, false);
       
   367         JInfo.main(newArgs.toArray(new String[newArgs.size()]));
       
   368     }
   333     }
   369 
   334 
   370     private static void runJSNAP(String[] oldArgs) {
   335     private static void runJSNAP(String[] oldArgs) {
   371         SAGetopt sg = new SAGetopt(oldArgs);
   336         Map<String, String> longOptsMap = Map.of("exe=", "exe",
   372         String[] longOpts = {"exe=", "core=", "pid=", "all"};
   337                                                  "core=", "core",
   373 
   338                                                  "pid=", "pid",
   374         ArrayList<String> newArgs = new ArrayList();
   339                                                  "connect=", "connect",
   375         String exe = null;
   340                                                  "all", "-a");
   376         String pid = null;
   341         Map<String, String> newArgMap = parseOptions(oldArgs, longOptsMap);
   377         String core = null;
   342         JSnap.main(buildAttachArgs(newArgMap, false));
   378         String s = null;
       
   379 
       
   380         while((s = sg.next(null, longOpts)) != null) {
       
   381             if (s.equals("exe")) {
       
   382                 exe = sg.getOptarg();
       
   383                 continue;
       
   384             }
       
   385             if (s.equals("core")) {
       
   386                 core = sg.getOptarg();
       
   387                 continue;
       
   388             }
       
   389             if (s.equals("pid")) {
       
   390                 pid = sg.getOptarg();
       
   391                 continue;
       
   392             }
       
   393             if (s.equals("all")) {
       
   394                 newArgs.add("-a");
       
   395                 continue;
       
   396             }
       
   397         }
       
   398 
       
   399         buildAttachArgs(newArgs, pid, exe, core, false);
       
   400         JSnap.main(newArgs.toArray(new String[newArgs.size()]));
       
   401     }
   343     }
   402 
   344 
   403     private static void runDEBUGD(String[] oldArgs) {
   345     private static void runDEBUGD(String[] oldArgs) {
   404         // By default SA agent classes prefer Windows process debugger
   346         // By default SA agent classes prefer Windows process debugger
   405         // to windbg debugger. SA expects special properties to be set
   347         // to windbg debugger. SA expects special properties to be set
   406         // to choose other debuggers. We will set those here before
   348         // to choose other debuggers. We will set those here before
   407         // attaching to SA agent.
   349         // attaching to SA agent.
   408         System.setProperty("sun.jvm.hotspot.debugger.useWindbgDebugger", "true");
   350         System.setProperty("sun.jvm.hotspot.debugger.useWindbgDebugger", "true");
   409 
   351 
   410         SAGetopt sg = new SAGetopt(oldArgs);
   352         Map<String, String> longOptsMap = Map.of("exe=", "exe",
   411         String[] longOpts = {"exe=", "core=", "pid=", "serverid="};
   353                                                  "core=", "core",
   412 
   354                                                  "pid=", "pid",
   413         ArrayList<String> newArgs = new ArrayList<>();
   355                                                  "serverid=", "serverid");
   414         String exe = null;
   356         Map<String, String> newArgMap = parseOptions(oldArgs, longOptsMap);
   415         String pid = null;
   357         var serverid = newArgMap.remove("serverid");
   416         String core = null;
   358         List<String> newArgArray = new ArrayList<>();
   417         String s = null;
   359         newArgArray.addAll(Arrays.asList(buildAttachArgs(newArgMap, false)));
   418         String serverid = null;
   360 
   419 
   361         // `serverid` must be located at the tail.
   420         while((s = sg.next(null, longOpts)) != null) {
       
   421           if (s.equals("exe")) {
       
   422               exe = sg.getOptarg();
       
   423               continue;
       
   424           }
       
   425           if (s.equals("core")) {
       
   426               core = sg.getOptarg();
       
   427               continue;
       
   428           }
       
   429           if (s.equals("pid")) {
       
   430               pid = sg.getOptarg();
       
   431               continue;
       
   432           }
       
   433           if (s.equals("serverid")) {
       
   434               serverid = sg.getOptarg();
       
   435               continue;
       
   436           }
       
   437         }
       
   438 
       
   439         buildAttachArgs(newArgs, pid, exe, core, false);
       
   440         if (serverid != null) {
   362         if (serverid != null) {
   441             newArgs.add(serverid);
   363             newArgArray.add(serverid);
   442         }
   364         }
   443 
   365 
   444         // delegate to the actual SA debug server.
   366         // delegate to the actual SA debug server.
   445         sun.jvm.hotspot.DebugServer.main(newArgs.toArray(new String[newArgs.size()]));
   367         DebugServer.main(newArgArray.toArray(new String[0]));
   446     }
   368     }
       
   369 
       
   370     // Key: tool name, Value: launcher method
       
   371     private static Map<String, Consumer<String[]>> toolMap =
       
   372         Map.of("clhsdb", SALauncher::runCLHSDB,
       
   373                "hsdb", SALauncher::runHSDB,
       
   374                "jstack", SALauncher::runJSTACK,
       
   375                "jmap", SALauncher::runJMAP,
       
   376                "jinfo", SALauncher::runJINFO,
       
   377                "jsnap", SALauncher::runJSNAP,
       
   378                "debugd", SALauncher::runDEBUGD);
   447 
   379 
   448     public static void main(String[] args) {
   380     public static void main(String[] args) {
   449         // Provide a help
   381         // Provide a help
   450         if (args.length == 0) {
   382         if (args.length == 0) {
   451             launcherHelp();
   383             launcherHelp();
   465         }
   397         }
   466 
   398 
   467         String[] oldArgs = Arrays.copyOfRange(args, 1, args.length);
   399         String[] oldArgs = Arrays.copyOfRange(args, 1, args.length);
   468 
   400 
   469         try {
   401         try {
   470             // Run SA interactive mode
   402             var func = toolMap.get(args[0]);
   471             if (args[0].equals("clhsdb")) {
   403             if (func == null) {
   472                 runCLHSDB(oldArgs);
   404                 throw new SAGetoptException("Unknown tool: " + args[0]);
   473                 return;
   405             } else {
   474             }
   406                 func.accept(oldArgs);
   475 
   407             }
   476             if (args[0].equals("hsdb")) {
       
   477                 runHSDB(oldArgs);
       
   478                 return;
       
   479             }
       
   480 
       
   481             // Run SA tmtools mode
       
   482             if (args[0].equals("jstack")) {
       
   483                 runJSTACK(oldArgs);
       
   484                 return;
       
   485             }
       
   486 
       
   487             if (args[0].equals("jmap")) {
       
   488                 runJMAP(oldArgs);
       
   489                 return;
       
   490             }
       
   491 
       
   492             if (args[0].equals("jinfo")) {
       
   493                 runJINFO(oldArgs);
       
   494                 return;
       
   495             }
       
   496 
       
   497             if (args[0].equals("jsnap")) {
       
   498                 runJSNAP(oldArgs);
       
   499                 return;
       
   500             }
       
   501 
       
   502             if (args[0].equals("debugd")) {
       
   503                 runDEBUGD(oldArgs);
       
   504                 return;
       
   505             }
       
   506 
       
   507             throw new SAGetoptException("Unknown tool: " + args[0]);
       
   508         } catch (SAGetoptException e) {
   408         } catch (SAGetoptException e) {
   509             System.err.println(e.getMessage());
   409             System.err.println(e.getMessage());
   510             toolHelp(args[0]);
   410             toolHelp(args[0]);
   511         }
   411         }
   512     }
   412     }