RFR(M): 8236913: debug agent's jdwp command logging should include the command set name and command name

Alex Menkov alexey.menkov at oracle.com
Wed Jan 15 22:05:00 UTC 2020


Hi Chris,

I'd prefer to not separate command handlers and names.

maybe something like

static Command ArrayReference_Commands[] = {
     {length, "Length"},
     {getValues, "GetValues"},
     {setValues, "SetValues"}
};

CommandSet ArrayReference_CommandSet = {
     3, "ArrayReference", &ArrayReference_Commands
};

--alex

On 01/15/2020 13:09, Chris Plummer wrote:
> Hi,
> 
> Unfortunately I'm going to have to redo this fix. I ran into compilation 
> problems on Solaris:
> 
> error: too many struct/union initializers (E_TOO_MANY_STRUCT_UNION_INIT)
> 
> This turns up on the first initializer of the cmds[] array:
> 
> CommandSet ArrayReference_Cmds = {
>      3, "ArrayReference",
>      {
>          {length, "Length"},   <----------
>          {getValues, "GetValues"},
>          {setValues, "SetValues"}
>      }
> };
> 
> It turns out that statically initializing a variable length array that 
> is a field of a struct is not valid C syntax. You can statically 
> initialize a variable length array, which is what the code was 
> originally doing, but not a variable length array within a struct.
> 
> I can fix this issue by giving the array a fixed size. For example:
> 
> typedef struct CommandSet {
>      int num_cmds;
>      const char *cmd_set_name;
>      const Command cmds[20];
> } CommandSet;
> 
> The catch here is that the array size needs to be at least as big as the 
> largest use, and for all the other static uses extra space will be 
> allocated but never used. In other words, all the arrays would be size 
> 20, even those that initialize fewer than 20 elements.
> 
> So the choice here pretty much keep what I have, but waste some space 
> with the fixed array size, or use parallel arrays to store the function 
> pointers and command names separately. We used to have:
> 
> void *ArrayReference_Cmds[] = { (void *)0x3
>      ,(void *)length
>      ,(void *)getValues
>      ,(void *)setValues};
> 
> I could just keep this as-is and add:
> 
> char *ArrayReference_CmdNames[] = {
>      "Length",
>      "GetValues",
>      "SetValues"
> };
> 
> A further improvement might be to change to original array to be:
> 
> const CommandHandler ArrayReference_Cmds[] = {
>      length,
>      getValues,
>      setValues
> };
> 
> And then I can add a #define for the array size:
> 
> #define ArrayReference_NumCmds (sizeof(ArrayReference_Cmds) / 
> sizeof(CommandHandler))
> 
> char *ArrayReference_CmdNames[ArrayReference_NumCmds] = {
>      "Length",
>      "GetValues",
>      "SetValues"
> };
> 
> Then I can either access these arrays in parallel, meaning instead of:
> 
>      cmdSetsArray[JDWP_COMMAND_SET(ArrayReference)] = &ArrayReference_Cmds;
> 
> I would have (not I need an array for the sizes also for the second 
> option abov):
> 
>      cmdSetsCmdsArraySize[JDWP_COMMAND_SET(ArrayReference)] = 
> ArrayReference_NumCmds;
>      cmdSetsCmdsArray[JDWP_COMMAND_SET(ArrayReference)] = 
> &ArrayReference_Cmds;
>      cmdSetsCmdNamesArray[JDWP_COMMAND_SET(ArrayReference)] = 
> &ArrayReference_CmdNames;
> 
> Or I could change the CommandSet definition to be:
> 
> typedef struct CommandSet {
>      int num_cmds;
>      const char *cmd_set_name;
>      CommandHandler cmd_handler[];
>      const char *cmd_name[];
> } CommandSet;
> 
> And then add:
> 
> const CommandSet ArrayReference_CommandSet = {
>      ArrayReference_NumCmds,
>      "ArrayReference",
>      &ArrayReference_Cmds,
>      &ArrayReference_CmdNames
> }
> 
> Then I would just have the array of CommandSets rather than 3 arrays to 
> deal with.
> 
> Lasty, I could use a macro that declares a new type for each CommandSet, 
> and then when the array of CommandSets is initialized, I would cast that 
> type to a CommandSet. I think the invocation of the macro would look 
> something like:
> 
> DEFINE_COMMAND_SET (3, ArrayReference,
>          {length, "Length"},
>          {getValues, "GetValues"},
>          {setValues, "SetValues"}
> )
> 
> However, I'm a bit unsure of this since I haven't made any attempt to 
> implement it yet. There might be more issues that pop up with this one, 
> where-as doing the parallel arrays is pretty straight forward (although 
> not pretty).
> 
> thoughts?
> 
> Chris
> 
> 
> On 1/10/20 11:27 AM, Chris Plummer wrote:
>> Hello,
>>
>> Please review the following
>>
>> https://bugs.openjdk.java.net/browse/JDK-8236913
>> http://cr.openjdk.java.net/~cjplummer/8236913/webrev.00/
>>
>> The debug agent has logging support that will trace all jdwp commands 
>> coming in. Currently all it traces is the command set number and the 
>> command number within that command set. So you see something like:
>>
>> [#|10.01.2020 06:27:24.366 
>> GMT|FINEST|J2SE1.5|jdwp|LOC=MISC:"debugLoop.c":240;;PID=12719;THR=t at 915490560|:Command 
>> set 1, command 9|#]
>>
>> I've added support for including the name of the command set and 
>> command, so now you see:
>>
>> [#|10.01.2020 06:27:24.366 
>> GMT|FINEST|J2SE1.5|jdwp|LOC=MISC:"debugLoop.c":240;;PID=12719;THR=t at 915490560|:Command 
>> set VirtualMachine(1), command Resume(9)|#]
>>
>> So in this case command set 1 represents VirtualMachine and command 9 
>> is the Resume command.
>>
>> I was initially going to leverage jdwp.spec which is already processed 
>> by build.tools.jdwpgen.Main to produce JDWP.java and JDWPCommands.h. 
>> However, I could see it was more of a challenge than I initially 
>> hoped. Also, the main advantage would have been not having to hard 
>> code arrays of command names, but we already have harded coded arrays 
>> of function pointers to handle the various jdwp commands, so I just 
>> replaced these with a more specialized arrays that also include the 
>> names of the commands. As an example, we used to have:
>>
>> void *ArrayReference_Cmds[] = { (void *)0x3
>>     ,(void *)length
>>     ,(void *)getValues
>>     ,(void *)setValues};
>>
>> Now we have:
>>
>> CommandSet ArrayReference_Cmds = {
>>     3, "ArrayReference",
>>     {
>>         {length, "Length"},
>>         {getValues, "GetValues"},
>>         {setValues, "SetValues"}
>>     }
>> };
>>
>> So no worse w.r.t. hard coding things that could be generated off the 
>> spec, and it cleans up some ugly casts also. The CommandSet typedef 
>> can be found in debugDispatch.h.
>>
>> All the header files except for debugDispatch.h have the same pattern 
>> for changes, so they are pretty easy to review
>>
>> All .c files except debugDispatch.c and debugLoop.c also have the same 
>> pattern. Note some command handler function names are not the same as 
>> the command name. If you want to double check command set names and 
>> command names, you can find the spec here:
>>
>> https://docs.oracle.com/javase/9/docs/specs/jdwp/jdwp-protocol.html
>>
>> In ReferenceTypeImpl.c I fixed a typo in the method() prototype. It 
>> had an extra argument which I think was a very old copy-n-paste bug 
>> from the method1() prototype. This was caught because the command 
>> handler functions are now directly assigned to a CommandHandler type 
>> rather than cast. The cast was hiding this bug.
>>
>> I tested by doing a test run where MISC logging was enabled by 
>> default. All jdwp, jdb, and jdi tests were run in this way and passed.
>>
>> thanks,
>>
>> Chris
>>
> 
> 


More information about the serviceability-dev mailing list