is there any way to make this class file generated by byte buddy contains LocalVariableTable? - byte-buddy

I am using byte buddy to print logs of methods automaticly,but i found that if i use byte buddy to regenerate class files,the LocalVariableTable will be overwritten and disappear.and that will make springmvc unfunctional because springmvc uses LocalVariableTable to get the names of args of methods,and if there is no LocalVariableTable, the programme will go wrong.so how can byte buddy generate a class file with LocalVariableTable?
here is how I used it:
DynamicType.Builder<?>.method((isPublic()
.and(not(isEquals()))
.and(not(isClone()))
.and(not(isToString()))
.and(not(isHashCode()))
.and(not(isDefaultMethod()))
.and(not(isDefaultConstructor()))
.and(not(isDefaultFinalizer()))
.and(not(isAbstract()))
.and(not(isStatic()))
.and(not(isSetter().or(isGetter()))))
.or(isAnnotatedWith(Hook.class)))
.intercept(Advice.to(MethodHooks.class));

If you use interception, you are defining a new method and the old method is backed-up to another location for being able to invoke it. This includes the debug table where this information is stored. You can however compile a class using the -parameters parameter. This more official information is retained by Byte Buddy.

Related

intercept field access to log with bytebuddy

I am trying to log field writes with bytebuddy. After reading some earlier posts, I started using MemberSubstitution and got something going using the following code:
private static Method FIELD_INTERCEPTOR = // reflective reference to interceptFieldWrite
AsmVisitorWrapper VISITOR = MemberSubstitution.relaxed()
.field(ElementMatchers.any())
.onWrite()
.replaceWith(FIELD_INTERCEPTOR)
.on(ElementMatchers.isMethod());
..
public static void interceptFieldWrite(Object object,Object value) {
System.out.println("intercepted field write in object " + object + " , attempt to set value to " + value);
}
..
The part I am struggling with is how to pass a reference to the field for which the access is intercepted to interceptFieldWrite (as string or instance of Field). If possible I would of course like to avoid reflection completely. I don't actually want to completely substitute field access, but just want to add a method with some checks just before it takes place. Is there a feature in bytebuddy to do this, or do I have to use something more low-level than ASM to achieve this ?
Byte Buddy offers this but you will have to compose your own StackManipulations to do so. The mechanism in MemberSubstitution is called replaceWithChain. Here you specify Steps where each step can do what you intend:
invoke a method via MethodInvocation.
write a field via FieldAccessor.
You will have to load the arguments to the method call and the field access prior to using the above stack manipulations via the MethodVariableAccess where the targeted element's offsets are represented by offsets.
In your case, this would require to read the target instance via
MethodVaribaleAccess.of(parameters.get(0)).loadFrom(offsets.get(0));
MethodVaribaleAccess.of(parameters.get(1)).loadFrom(offsets.get(1));
and the to execute the method or field write in question. The targeted field will be passed as target, you can cast it to FieldDescription if you only ever intercept fields.
Make sure you only intercept non-static fields where the this instance will not be passed.

How do I use MethodCall.invoke(someElementMatcher) to create a MethodCall representing a method I subsequently define in an instrumented type?

I am using ByteBuddy to generate a class.
Prior to working with DynamicType.Builder, I was going to store a MethodCall as an instance variable:
private final MethodCall frobCall =
MethodCall.invoke(ElementMatchers.named("frob")); // here I invoke a method I'm going to define as part of the instrumented type
Then later in my generation logic for the instrumented type I define the frob method to do something:
.defineMethod("frob")
.intercept(...etc....) // here I define frob to do something
…and I define the (let's say) baz method to invoke frob:
.defineMethod("baz")
.withParameter(...) // etc.
.intercept(frobCall); // invokes "frob", which I've just defined above
(I am trying to keep this simple and may have mistyped something but I hope you can see the gist of what I'm trying to do.)
When I make() my DynamicType, I receive an error that indicates that the dynamic type does not define frob. This is mystifying to me, because of course I have defined it, as you can see above.
Is there some restriction I am unaware of that prohibits ElementMatchers from identifying instrumented type methods that are defined later? Do I really have to use MethodDescription.Latent here?
It should match all methods of the instrumented type. If this is not happening as expected, please set a breakpoint in MethodCall.MethodLocator.ForElementMatcher to see why the method is not showing up. I assume it is filtered by your method matcher.
I noticed however that it did not include private methods which is now fixed and will be released within Byte Buddy 1.10.18.

How can I retrieve the is_sfparam-content while printing RECN contracts?

How can i retrieve the is_sfparam-content, either using query or function module.
then will be passed as a parameter to cl_recp_data_cn_general=>get_contract.
do you have any idea? Where can I get that is_sfparam-content?
Thanks
CALL METHOD cl_recp_data_cn_general=>get_contract
EXPORTING
id_guid = is_sfparam-content
IMPORTING
es_contract = contract
CHANGING
cf_error = lf_error.
This guid paramater brings no sense as it is generated in runtime. You can check this yourself by putting breakpoint at the first line (e.g. line 102) of method cl_recp_data_cn_general=>get_contract and checking id_guid var in debugger. It will be different with each run of preview in RECN tcode.
Check also line 11 of CONSTRUCTOR method of CL_RECP_SF_DOC class, it is executed during each form generation.
The real contract object lays in variable go_busobj of program SAPLRECA_BDT_APPL_TOOL which brings RECN functionality and it is global i.e. it is loaded into memory constantly while RECN is running, just passing doc object into called methods thru the call stack, which you can follow in debugger.
Where really form generation takes place is CL_RECP_SF_JOB class, for preview it is _FP_PREVIEW method, for print it is _FP_PRINT. For example, in preview method form FM is called in that place
What you need to do if you want to call arbitrary contract print-form, which is what I assume you want to do by asking this question:
Find out smartform FM name by putting breakpoint in the above line
Build parameters for this FM calling. The only obligatory parameter is LS_SFPARAM-CONTENT which is the GUID.
You can generate this GUID manually by creating CL_RECP_SF_DOC object, let it be io_doc var. The constructor of this object has input parameter is_doc which should be filled according to the attributes of contract which you want to print, and which are stored in VIBDRO and VICNCN tables.
After creating this object pass its attribute io_doc->md_guid to ls_sfparam-content, generate other parameters with CL_RECP_SF_JOB->_sf_get_form_param and
Run the smartform FM /1BCDWB/SF000000XX found at step 1 with these parameters
I didn't check all these steps by myself but I believe it should work.

writing module to .bc bitcode file

i've assumed that dumping a .bc file from a module was a trivial operation, but now,
first time i have to actually do it from code, for the life of me i
can't find one missing step in the process:
static void WriteModule ( const Module * M, BitstreamWriter & Stream )
http://llvm.org/docs/doxygen/html/BitcodeWriter_8cpp.html#a828cec7a8fed9d232556420efef7ae89
to write that module, first i need a BistreamWriter
BitstreamWriter::BitstreamWriter (SmallVectorImpl< char > &O)
http://llvm.org/docs/doxygen/html/classllvm_1_1BitstreamWriter.html
and for a BitstreamWriter i need a SmallVectorImpl. But, what next?
Should i write the content of the SmallVectorImpl byte by byte on a
file handler myself? is there a llvm api for this? do i need something
else?
The WriteModule function is static within lib/Bitcode/Writer/BitcodeWriter.cpp, which means it's not there for outside consumption (you can't even access it).
The same file has another function, however, called WriteBitcodeToFile, with this interface:
/// WriteBitcodeToFile - Write the specified module to the specified output
/// stream.
void llvm::WriteBitcodeToFile(const Module *M, raw_ostream &Out);
I can't imagine a more convenient interface. The header file declaring it is ./include/llvm/Bitcode/ReaderWriter.h, by the way.
I use following code :
std::error_code EC;
llvm::raw_fd_ostream OS("module", EC, llvm::sys::fs::F_None);
WriteBitcodeToFile(pBiFModule, OS);
OS.flush();
and then disassemble using llvm-dis.

Java: Why method type in .class file contains return type, not only signature?

There is a "NameAndType" structure in the constants pool in .class file.
It is used for dynamic binding.
All methods that class can "export" described as "signature + return type".
Like
"getVector()Ljava/util/Vector;"
That breakes my code when return type of the method in some .jar is changed, even if new type is narrower.
i.e:
I have the following code:
List l = some.getList();
External .jar contains:
public List getList()
Than external jar changes method signature to
public ArrayList getList().
And my code dies in run-time with NoSuchMethodException, because it can't find
getList()Ljava/util/List;
So, I have to recompile my code.
I do not have to change it. Just recompile absolutely the same code!
That also gives ability to have two methods with one signature, but different return types! Compiler would not accept it, but it is possible to do it via direct opcoding.
My questions is why?
Why they did it?
I have only one idea: to prevent sophisticated type checking in the runtime.
You need to look up to the hierarchy and check if there is a parent with List interface.
It takes time, and only compiler has it. JVM does not.
Am I right?
thanks.
One reason may be because method overloading (as opposed to overriding) is determined at compile time. Consider the following methods:
public void doSomething(List util) {}
public void doSomething(ArrayList util) {}
And consider code:
doSomething(getList());
If Java allowed the return type to change and did not throw an exception, the method called would still be doSomething(List) until you recompiled - then it would be doSomething(ArrayList). Which would mean that working code would change behavior just for having recompiled it.