Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is it possible to find all references to some object? #26

Closed
unikoid opened this issue Sep 18, 2016 · 23 comments
Closed

Is it possible to find all references to some object? #26

unikoid opened this issue Sep 18, 2016 · 23 comments

Comments

@unikoid
Copy link

unikoid commented Sep 18, 2016

Hello,

First, thank you for the job you've done, llnode is great debugging tool.

mdb_v8 findjsobjects command has one useful feature:

-r Find references to the specified and/or marked object(s)

Is it possible to achieve the same with lldb + llnode? If not, do you have any plans to implement this feature?

@indutny
Copy link
Member

indutny commented Sep 18, 2016

cc @hhellyer

@hhellyer
Copy link
Collaborator

It should be fairly practical. For the nodeinfo command I used the logic from @indutny's inspect functions to return object ref's directly (instead of as strings) which is the core of what this command would need.

I can try and take a look at doing this this week. Would it be best to make it an extension of findjsobjects so it's familiar to mdb_v8 users or a new command since it probably won't be exactly the same as the mdb version and might have it's own set of options?

@indutny
Copy link
Member

indutny commented Sep 19, 2016

It makes sense to me to create an extension for it. As an less compatible alias we could use v8 findrefs, I guess?

@indutny
Copy link
Member

indutny commented Sep 19, 2016

@hhellyer thanks for the heads up!

@unikoid
Copy link
Author

unikoid commented Sep 20, 2016

Thanks a lot. It would be great to see this feature in llnode.

Little offtopic:
By the way, I guess it's possible to find refs by means of lldb scripting tools. This may be a temporary solution until you implement "native"findrefs cmd in llnode.
I've looked over lldb documentation briefly, but I'm unable to figure out any ways to call lldb plugin methods from script and access their output.
I would highly appreciate if anyone could help me with this.

@hhellyer
Copy link
Collaborator

@unikoid It's not looking to difficult to add. I'll hopefully put up a branch with a prototype sometime this week. Are there any features other than just simply listing all the objects that refer to another object that you need? (I was going to put the referring object id, it's name and the referring field name in the output.

How are you trying to load the plugin? From the python interface or C++? I'm not sure the lldb API docs are that up to date but I have the source checked out so if you can be a bit more specific I can check that.

@indutny
Copy link
Member

indutny commented Sep 20, 2016

@hhellyer I think there is a way to write a python script that will just execute various commands. I doubt that it will be efficient, though.

@hhellyer
Copy link
Collaborator

The whole LLDB SB (Scripting Bridge) API is mirrored from C++ to Python using SWIG so theoretically you can do anything in Python that you can do in C++. Unfortunately I don't believe there's a call to load a plugin in the API. Searching for calls to the plugin loading function only hits the code for the "plugin load" command. I don't think the plugin loading feature is exposed.

You could get around it by loading the llnode code as a library and calling into it but it's probably quite a lot of work. I'll try and make a prototype for findrefs available soon.

@rnchamberlain
Copy link
Contributor

@yjhjstz has been using the C++ scripting interface to call plugin commands, see https://github.com/yjhjstz/llnode. I think he issues the 'plugin load' command first via the SBCommandInterpreter, then the llnode commands.

lldb::SBCommandInterpreter` interpreter = debugger.GetCommandInterpreter();
interpreter.HandleCommand(command_line, command_result, false);

As Fedor says, it is likely to be a bit inefficient if the entire heap is being scanned

@hhellyer
Copy link
Collaborator

@unikoid - I've put a (very rough) prototype here: https://github.com/hhellyer/llnode/tree/findreferences_prototype
feel free to give it a go. The code is definitely not final, apart from needing clean up and my to-dos fixing it also seems to have a bug finding references in arrays.
It's not production ready (I wouldn't rely on it yet) but on the other hand that means it's a good time to suggest changes! Feedback on the format of the output is especially welcome.

@unikoid
Copy link
Author

unikoid commented Sep 22, 2016

@hhellyer Good news, thanks a lot!
I'll try it ASAP.

@hhellyer
Copy link
Collaborator

@unikoid - I've pushed an update. References in arrays (or rather references in elements, indexed by number rather than name) should now be found.

@unikoid
Copy link
Author

unikoid commented Sep 23, 2016

@hhellyer I tried your prototype, but it seems to be not working for my case.
v8 findrefs <addr> just stucks and never returns on my core dump and lldb is eating 100% CPU at this time.

This may be a problem with my dump, though, as v8 bt gives me rather strange trace without JS frames at all, maybe I've occasionally corrupted the dump itself a few days ago. But other v8 commands work well on this dump and mdb_v8 shows correct trace.

I'll retry with another dump a bit later.

@hhellyer
Copy link
Collaborator

@unikoid - It should work if the findjsobjects command is working, they use the same code for locating all objects in memory.
Are you using the LLNODE_RANGESFILE to point to a file of memory ranges? (Or building against lldb-3.9 where this isn't required.)

@unikoid
Copy link
Author

unikoid commented Sep 23, 2016

@hhellyer
findjsobjects works fine and takes about two minutes. Yes, I use LLNODE_RANGESFILE.

@hhellyer
Copy link
Collaborator

@unikoid Ok, I've tried it on a dump with a much fuller heap and it's taking a while for me too. I'll investigate further to see if I can find out why and if I can improve the performance.

@hhellyer
Copy link
Collaborator

@unikoid Ok, so the problem was I was getting every property name in every object (inflating those to strings) then looking up the value for those. I've got a local patch that gets back all the name/value pairs and checks the value of the ref before inflating the key name. That results in a pretty huge speed up in local testing.

I'll tidy it up and push it to the prototype branch on Monday.

@hhellyer
Copy link
Collaborator

@unikoid I've pushed an update that should give much better performance when running findrefs.

String creation is also the highest profiling part of the findjsobjects command so I might take a look and see if I can improve that sometime but if I do I'll do it under a separate issue.

@unikoid
Copy link
Author

unikoid commented Sep 28, 2016

@hhellyer thanks, I tried the latest version, but still no luck. I'm going to try to debug this myself today.

@unikoid
Copy link
Author

unikoid commented Sep 30, 2016

@hhellyer I tried to debug it a bit.
Looks like llnode finds some array with length 1919247987 and iterates over it. Hardly my application may produce THAT long array, so this may be a bug of GetType or smth. I continue investigation.

Could you please help me with one question:
I tried to inspect this long "array" with lldb, so I did:

(lldb) frame variable js_obj
(llnode::v8::JSObject &) js_obj = 0x00007fff545aa3b0: {
  llnode::v8::HeapObject = {
    llnode::v8::Value = {
      v8_ = 0x000000012d59da08
      raw_ = 1499008805665
    }
  }
}

while being inside of PrintRefs method. As far as I understand, v8_ contains an address, that may than be used with llnode inspect command. But v8 inspect 0x000000012d59da08 says it is <Smi: 1>.

@hhellyer
Copy link
Collaborator

hhellyer commented Sep 30, 2016

@unikoid It's the raw_ field that contains the address you should use with v8 inspect. The v8_ field is a reference to llnodes v8::LLV8 C++ object.

v8 inspect 1499008805665

should show you the object. If you post the output I'll see if there's anything I can do.

@unikoid
Copy link
Author

unikoid commented Sep 30, 2016

@hhellyer thanks.
Btw, do you have any ideas about any reason for this:

(lldb) v8 inspect 1499008805665
error: Failed to evaluate expression

?

@hhellyer
Copy link
Collaborator

I see that sometimes when the address doesn't point to a well formed object for some reason.

It might be worth just checking the dump you are using. How did you generate it?

I think the ones generated by --abort_on_uncaught_exception are likely to be safe but the rest of the time v8 could be doing anything. A dump generated mid-garbage collection is likely to be bad but the rest of the time depending on when and how the dump was created there could be half formed objects on the heap which I wouldn't be surprised to find causing problems.

hhellyer referenced this issue in hhellyer/llnode Oct 5, 2016
Add implemenetation of v8 findrefs that searchs for objects that
refer to the object id passed to v8 findrefs.
Displays the object id of the referrer and the field name that referred
to the object id.

Example:
(lldb) v8 findrefs 0x00003a1aca0e3051
0x3a1aca0e3369: Object.obj=0x3a1aca0e3051

Fixes: https://github.com/indutny/llnode/issues/26
hhellyer referenced this issue in hhellyer/llnode Oct 12, 2016
Add implementation of v8 findrefs that searches for objects that
refer to the object id passed to v8 findrefs.
Displays the object id of the referrer and the field name that referred
to the object id.

Example:
(lldb) v8 findrefs 0x00003a1aca0e3051
0x3a1aca0e3369: Object.obj=0x3a1aca0e3051

Fixes: https://github.com/indutny/llnode/issues/26
Review: nodejs#32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants