How to log function names and properties accessed from javascript code?

33 views
Skip to first unread message

jun5...@gmail.com

unread,
Apr 15, 2020, 3:20:20 AM4/15/20
to v8-dev
Hello, 

For research reason, I need to log all the function names and properties accessed from javascript. Given the below example code from a webpage:

<script>
      console.log('test");
      window.name="new name";
</script>

I'd like to capture that 'console.log()' and 'window.name' have been accessed.


I'm quite new to v8 development. I've been struggling with the v8 source code in the chromium for a while. 
Could anyone save my life by giving me some hints or code snippets to get started?


Jakob Kummerow

unread,
Apr 15, 2020, 7:53:46 AM4/15/20
to v8-...@googlegroups.com
The first part of this is easy: the existing --trace flag traces all function calls. If printing to stdout is not what you need, you can at least grep for FLAG_trace in the code to see where you'd have to add your own code.

The second part, logging all accessed properties, seems considerably harder -- I'm not sure how to do it. As a start, you can turn off ICs, and add code to the RUNTIME_FUNCTIONs you see in ic.cc. But that leaves a bunch of implicit property loads inside built-in functions, and those don't go through any common bottlenecks, so you'd have to find them all by hand. It's going to be a lot of work.

Mythri Alle

unread,
Apr 15, 2020, 1:00:20 PM4/15/20
to v8-...@googlegroups.com
On Wed, Apr 15, 2020 at 12:53 PM Jakob Kummerow <jkum...@chromium.org> wrote:
The first part of this is easy: the existing --trace flag traces all function calls. If printing to stdout is not what you need, you can at least grep for FLAG_trace in the code to see where you'd have to add your own code.

The second part, logging all accessed properties, seems considerably harder -- I'm not sure how to do it. As a start, you can turn off ICs, and add code to the RUNTIME_FUNCTIONs you see in ic.cc. But that leaves a bunch of implicit property loads inside built-in functions, and those don't go through any common bottlenecks, so you'd have to find them all by hand. It's going to be a lot of work.

Also turn off lazy feedback allocation (--no-lazy-feedback-allocation) along with turning off ICs. Without feedback vectors, we take a slightly different path to load some properties and may not call runtime functions. That still doesn't help with implicit property loads mentioned by Jakob.

On Wed, Apr 15, 2020 at 9:20 AM <jun5...@gmail.com> wrote:
Hello, 

For research reason, I need to log all the function names and properties accessed from javascript. Given the below example code from a webpage:

<script>
      console.log('test");
      window.name="new name";
</script>

I'd like to capture that 'console.log()' and 'window.name' have been accessed.


I'm quite new to v8 development. I've been struggling with the v8 source code in the chromium for a while. 
Could anyone save my life by giving me some hints or code snippets to get started?

--
--
v8-dev mailing list
v8-...@googlegroups.com
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to v8-dev+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/v8-dev/CAKSzg3T0qJSaZjRY2gSW%3DnTbjCBV6NAEEXhN9z9WQUjt9URqrg%40mail.gmail.com.

jun5...@gmail.com

unread,
Apr 15, 2020, 1:17:57 PM4/15/20
to v8-dev
Hi Jakob,

Thanks for your answer.

Regarding logging properties:
What if capturing a few targeted functions and properties only? I have a list of them (~30 built-in JS APIs or properties), including window.name, document.cookie, localStorage.setItem(), etc.
Will this make life easier? If yes, should I still follow the same direction as you suggested?

Regarding logging functions:
I've been trying to use the following code (get from this link at StackOverflow):
global->Set(v8::String::NewFromUtf8(isolate, "eval"), v8::FunctionTemplate::New(isolate, MY_LOGGING_FUNCTION));
Unfortunately, I didn't make this work. By any chance do you know the right place to put this code in order to trigger MY_LOGGING_FUNCTION.

BTW, while searching before I post this topic, I notice you answered lots of questions in the group. Just want to say thanks again. 

Seth Brenith

unread,
Apr 15, 2020, 2:55:56 PM4/15/20
to v8-dev
That sounds like a scenario that shouldn't need any modification of V8 itself, since JavaScript gives you a lot of control to override how properties behave. Here's a (not very well-tested, and probably with bugs) function to enable logging of a particular property:

function enableLogging(obj, name) {
  var descriptor = Object.getOwnPropertyDescriptor(obj, name);
  if (!descriptor) {
    // Prop isn't on that object, maybe a prototype?
    obj = Object.getPrototypeOf(obj);
    if (!obj) {
      throw new Error("can't find property");
    }
    return enableLogging(obj, name);
  }
  if (!descriptor.configurable) {
    throw new Error("can't reconfigure property");
  }
  if (descriptor.get) {
    var originalGet = descriptor.get;
    descriptor.get = function () {
      var result = originalGet.apply(this, arguments);
      console.log("got " + name, result);
      return result;
    };
  }
  if (descriptor.set) {
    var originalSet = descriptor.set;
    descriptor.set = function (v) {
      console.log("setting " + name, v);
      return originalSet.apply(this, arguments);
    };
  }
  if (descriptor.value) {
    var value = descriptor.value;
    delete descriptor.value;
    descriptor.get = function () {
      console.log("got " + name, value);
      return value;
    };
    if (descriptor.writable) {
      delete descriptor.writable;
      descriptor.set = function (v) {
        console.log("setting " + name, v);
        value = v;
      };
    }
  }
  Object.defineProperty(obj, name, descriptor);
}

Then you just call it like enableLogging(document, "cookie") for whichever properties are of interest, and it will print to the developer console. I guess there might be a further step if you need this to automatically write to a file or something; maybe then you'd need to replace console.log with some custom function.

Seth Brenith

unread,
Apr 15, 2020, 2:58:18 PM4/15/20
to v8-dev
Well, I did say "probably with bugs", and I already spotted one. Updated inline; it should check "value" in descriptor rather than descriptor.value.


On Wednesday, April 15, 2020 at 11:55:56 AM UTC-7, Seth Brenith wrote:
That sounds like a scenario that shouldn't need any modification of V8 itself, since JavaScript gives you a lot of control to override how properties behave. Here's a (not very well-tested, and probably with bugs) function to enable logging of a particular property:

function enableLogging(obj, name) {
  var descriptor = Object.getOwnPropertyDescriptor(obj, name);
  if (!descriptor) {
    // Prop isn't on that object, maybe a prototype?
    obj = Object.getPrototypeOf(obj);
    if (!obj) {
      throw new Error("can't find property");
    }
    return enableLogging(obj, name);
  }
  if (!descriptor.configurable) {
    throw new Error("can't reconfigure property");
  }
  if (descriptor.get) {
    var originalGet = descriptor.get;
    descriptor.get = function () {
      var result = originalGet.apply(this, arguments);
      console.log("got " + name, result);
      return result;
    };
  }
  if (descriptor.set) {
    var originalSet = descriptor.set;
    descriptor.set = function (v) {
      console.log("setting " + name, v);
      return originalSet.apply(this, arguments);
    };
  }
  if ("value" in descriptor) {

jun5...@gmail.com

unread,
Apr 15, 2020, 3:13:14 PM4/15/20
to v8-dev
Hello Seth, 

Really appreciate your code here. 
Indeed, I've done this before using a browser extension to instrument JavaScript APIs and properties, so that for each webpage visit I can log and save API/property access.

However, at this time, I have to dive into the V8 source code ideally. I am building my utility functions upon an existing project that released an instrumented Chromium/V8.
I'll consider the JavaScript way to do this like you code illustrated, if I can't figure out a way from the V8 source code.

Just curious, are you guys Chromium/V8 developers? I feel like people in the group really share a lot. It's so nice.




On Wednesday, April 15, 2020 at 11:55:56 AM UTC-7, Seth Brenith wrote:

jun5...@gmail.com

unread,
Apr 15, 2020, 3:23:26 PM4/15/20
to v8-dev
Hi Mythri,

Thanks for your notes.

I've been exploring ic.cc as suggested by Jakob, and I found that in this source code:
MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) {}
The name variable carries the name of the property. For example, for the code below,
<script>
      console.log('test");
      window.name="new name";
</script>
I will get "console" and "window" if I print the name variable. By any chance do you know how to get log of console.log and name of window.name?



To unsubscribe from this group and stop receiving emails from it, send an email to v8-...@googlegroups.com.

Jakob Kummerow

unread,
Apr 15, 2020, 4:30:08 PM4/15/20
to v8-...@googlegroups.com
I've been exploring ic.cc as suggested by Jakob, and I found that in this source code:
MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) {}
The name variable carries the name of the property. For example, for the code below,
<script>
      console.log('test");
      window.name="new name";
</script>
I will get "console" and "window" if I print the name variable. By any chance do you know how to get log of console.log and name of window.name?

You should see another call to one of those functions. There are two loads in a row: first "window.console", then "console.log", so name is first "console" (and object is the global object) and then "log" (and object is the console object).
If --no-lazy-feedback-allocation is not enough to see that second load, then you may have to hack more of the source. Grep for "LoadIC", try to understand how it works when it's in "uninitialized" state, and see if there's anything you need to disable to make it take the "miss" branch (to call the runtime) in that case. I seem to recall that we moved the "uninitialized" -> "premonomorphic" transition to generated code at some point, but I think the code has changed quite a bit more since I last looked at it.

What if capturing a few targeted functions and properties only? I have a list of them (~30 built-in JS APIs or properties), including window.name, document.cookie, localStorage.setItem(), etc.
Will this make life easier? If yes, should I still follow the same direction as you suggested?

Well, you can see if you just want to find all their implementations and directly hook into there. The three examples you mentioned are all in Blink somewhere (start looking in https://source.chromium.org/chromium/chromium/src/+/master:third_party/blink/renderer/platform/bindings/). I'm not sure which is easier.

Frankly, I like Seth's idea better to do it all in JS. You could bundle a Chrome extension with your instrumented Chrome build that injects the respective code into every page.

Zhiju Yang

unread,
Apr 15, 2020, 9:39:15 PM4/15/20
to v8-dev
Just in case anyone in the future runs into the same position as mines. I am leaving some notes here.

First of all, I didn't make it happen as I decided to go with the JavaScript approach.
As you can imagine, it should work and will work as long as you give it enough time and effort. Since I don't have that much time for exploration, I gave up.

Second, I would suggest you rethink your situation: DO YOU REALLY NEED TO DO IT BY MODIFYING V8?
From the time and effort I spent, I can tell it is really complex and will take you lots of time if you are a starter like me.

Third, from what Seth mentioned in this thread and what I've done in my previous project, logging function and property access via JavaScript (e.g., in a browser extension) are pretty straightforward. 
So if your answer to the above question is NO, I'd suggest you go with the JavaScript approach. In my case, it makes my life way easier.
If anyone in the future would like more details about the JavaScript approach, I'd like to offer my help.

WARNING: these are just suggestions from a beginner, NOT AN EXPERT.
-----------------------------------------------------------------------------------------------------------
Last, I would thank Jakob, Mythri, Seth again. Thank you all for answering my questions here. Being an expert in such a great project and keeping sharing your experience and knowledge to help others is SO COOL. I really appreciate you all doing this.
Reply all
Reply to author
Forward
0 new messages