M3 R3.2: instrument-grpc-nonstream also captures out/ref byte[] responses
Extends the IL-rewrite to log out (byref) byte[] params at method exit (ldarg + ldind.ref), not just byte[] inputs. This captured GetTagInfosFromName's response, which located the per-tag GUID at offset 8 = exactly where ParseTagInfoRecord reads "typeId" — proving the SDK already parses the GUID AddStreamValues needs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B6mcaT2PjRFKcogzp9UkfC
This commit is contained in:
@@ -1401,7 +1401,7 @@ static int InstrumentGrpcNonStream(string[] args)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Input byte[] params are "System.Byte[]"; out/ref byte[] are "System.Byte[]&".
|
// ENTRY: log non-byref byte[] inputs ("System.Byte[]").
|
||||||
foreach (dnlib.DotNet.Parameter bufParam in method.Parameters
|
foreach (dnlib.DotNet.Parameter bufParam in method.Parameters
|
||||||
.Where(p => !p.IsHiddenThisParameter && p.Type.FullName == "System.Byte[]")
|
.Where(p => !p.IsHiddenThisParameter && p.Type.FullName == "System.Byte[]")
|
||||||
.ToArray())
|
.ToArray())
|
||||||
@@ -1425,10 +1425,49 @@ static int InstrumentGrpcNonStream(string[] args)
|
|||||||
Type = type.Name.String,
|
Type = type.Name.String,
|
||||||
Method = method.Name.String,
|
Method = method.Name.String,
|
||||||
Phase = phase,
|
Phase = phase,
|
||||||
Param = bufParam.Name,
|
Direction = "in",
|
||||||
Token = "0x" + method.MDToken.Raw.ToString("X8"),
|
Token = "0x" + method.MDToken.Raw.ToString("X8"),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EXIT: log out/ref byte[] responses ("System.Byte[]&") before each ret. ldarg loads the
|
||||||
|
// managed pointer; ldind.ref dereferences it to the byte[]. (RPC wrappers set the out
|
||||||
|
// param right before a single ret, so branch-to-ret skew is not a concern here.)
|
||||||
|
dnlib.DotNet.Parameter[] outParams = method.Parameters
|
||||||
|
.Where(p => !p.IsHiddenThisParameter && p.Type.FullName == "System.Byte[]&")
|
||||||
|
.ToArray();
|
||||||
|
if (outParams.Length > 0)
|
||||||
|
{
|
||||||
|
Instruction[] rets = method.Body.Instructions.Where(i => i.OpCode == OpCodes.Ret).ToArray();
|
||||||
|
foreach (Instruction ret in rets)
|
||||||
|
{
|
||||||
|
var exit = new List<Instruction>();
|
||||||
|
foreach (dnlib.DotNet.Parameter op in outParams)
|
||||||
|
{
|
||||||
|
exit.Add(Instruction.Create(OpCodes.Ldstr, $"{type.Name}.{method.Name}.{op.Name}.out"));
|
||||||
|
exit.Add(Instruction.Create(OpCodes.Ldarg, op));
|
||||||
|
exit.Add(Instruction.Create(OpCodes.Ldind_Ref));
|
||||||
|
exit.Add(Instruction.Create(OpCodes.Call, logByteArray));
|
||||||
|
}
|
||||||
|
int retIndex = method.Body.Instructions.IndexOf(ret);
|
||||||
|
foreach (Instruction instruction in ((IEnumerable<Instruction>)exit).Reverse())
|
||||||
|
{
|
||||||
|
method.Body.Instructions.Insert(retIndex, instruction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
method.Body.MaxStack = (ushort)Math.Max((int)method.Body.MaxStack, 8);
|
||||||
|
foreach (dnlib.DotNet.Parameter op in outParams)
|
||||||
|
{
|
||||||
|
instrumented.Add(new
|
||||||
|
{
|
||||||
|
Type = type.Name.String,
|
||||||
|
Method = method.Name.String,
|
||||||
|
Phase = $"{type.Name}.{method.Name}.{op.Name}.out",
|
||||||
|
Direction = "out",
|
||||||
|
Token = "0x" + method.MDToken.Raw.ToString("X8"),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user