2

I have a couple of JavaScript scripts to house my functions (for modularity and reuse). I load them both from the windbg script I'm running. From within one script, how do I call a function defined in the other?

This engine doesn't seem to support the import/export feature employed by browsers.

From within the debugger script, I have to use @$scriptContents to access JavaScript functions. How do I accomplish something similar from within one of the JavaScript functions?

Experiment

I was hoping there would be some sort of global namespace for all JavaScript functions, but it appears not.

Consider

// t1.js
function func1() {
    host.diagnostics.debugLog('func1()...\n');
}

and

// t2.js
function func2() {
    host.diagnostics.debugLog('func2()...\n');
    func1();
}

In my cdb session

0:000> .load jsprovider.dll
0:000> .scriptload t1.js
JavaScript script successfully loaded from 't1.js'
0:000> .scriptload t2.js
JavaScript script successfully loaded from 't2.js'
0:000> dx @$scriptContents.func1()
func1()...
@$scriptContents.func1()
0:000> dx @$scriptContents.func2()
func2()...
Error: 'func1' is not defined [at t2 (line 3 col 5)]

Edit

Per @Mosè Raguzzini's comment and this answer, I went looking for some way to reference "foreign" functions. I eventually unearthed this

host.namespace.Debugger.State.DebuggerVariables.scriptContents

as a container for all functions. Is this documented somewhere? Is there no simpler way to get there? (I realize I can just assign a short variable to that object; I'm just suspicious this this is more of a backdoor into something with a very simple front door, but I don't know where the front door is.)

mojo
  • 4,050
  • 17
  • 24
  • 1
    https://stackoverflow.com/questions/48243964/how-do-i-share-javascript-code-between-files-in-windbg-preview/48309639#48309639 – blabb Aug 01 '19 at 14:04

2 Answers2

1

AFAIK all scripts are imported in global scope, so you can act as them are written in a single file, once all are loaded.

Example (REF to blabb answer)

common.js has a few functions that are normally reusable like host.diagnostics.debugLog()

First load it using .scriptload

Then in other js files create a var to those functions and use it

contents of common function file

C:\>cat c:\wdscr\common.js
function log(instr) {
    host.diagnostics.debugLog(instr + "\n");
}
function exec (cmdstr){
    return host.namespace.Debugger.Utility.Control.ExecuteCommand(cmdstr);
}

a js file using the function from common.js

C:\>cat c:\wdscr\usecommon.js
function foo(){
    var commonlog = host.namespace.Debugger.State.Scripts.common.Contents.log
    var commonexec = host.namespace.Debugger.State.Scripts.common.Contents.exec
    commonlog("we are using the logging function from the common.js file")

    var blah = commonexec("lma @$exentry")
    for(var a of blah) {
        commonlog(a)
    }
}

actual usage

C:\>cdb calc
Microsoft (R) Windows Debugger Version 10.0.16299.15 X86

0:000> .load jsprovider

0:000> .scriptload c:\wdscr\common.js
JavaScript script successfully loaded from 'c:\wdscr\common.js'

0:000> .scriptload c:\wdscr\usecommon.js
JavaScript script successfully loaded from 'c:\wdscr\usecommon.js'

0:000> dx @$scriptContents.foo()

we are using the logging function from the common.js file 
start    end        module name
00f10000 00fd0000   calc       (deferred)
@$scriptContents.foo()
0:000>
Mosè Raguzzini
  • 15,399
  • 1
  • 31
  • 43
  • My experience does not bear this assumption out. See my edit. – mojo Aug 01 '19 at 12:51
  • From docs: 'When a script is loaded using the .scriptload command, the intializeScript function and the root code of the script is executed, the names which are present in the script are bridged into the root namespace of the debugger (dx Debugger) and the script stays resident in memory until it is unloaded and all references to its objects are released.' – Mosè Raguzzini Aug 01 '19 at 12:57
  • So, from within one script, how do I call one of the functions in a foreign script? – mojo Aug 01 '19 at 13:09
  • So, `host.namespace.Debugger.State.Scripts.common.Contents` is the only way? This doesn't seem quite like a "global namespace" except for the introspective features of the object model. – mojo Aug 01 '19 at 13:25
  • It's the way I know about – Mosè Raguzzini Aug 01 '19 at 13:26
  • That sounds like all the "documentation" I can find for WinDbg and JavaScript. (-8 – mojo Aug 01 '19 at 13:28
  • @mose is that a complete copy paste :) – blabb Aug 01 '19 at 14:06
  • Sorry, it was an edit to clarify my sentence for OP, added a ref to your answer ASAP – Mosè Raguzzini Aug 01 '19 at 14:38
1

well you can write a javascript function that calls any function from any script sitting in any directory

using something like below (you may need to tweak it the POC worked on my machine for a .js that returned a string)

function runFuncFromAnyScript(dir,script,somefunc) {
    var unl = ".scriptunload " + script
    host.namespace.Debugger.Utility.Control.ExecuteCommand(unl)
    var pre = ".scriptload "
    var post = "dx @$scriptContents." + somefunc
    var cmd  = pre + dir + script 
    host.namespace.Debugger.Utility.Control.ExecuteCommand(cmd)
    return host.namespace.Debugger.Utility.Control.ExecuteCommand(post)
}

used like

0:000> dx @$scriptContents.runFuncFromAnyScript("f:\\zzzz\\wdscript\\","mojo.js","hola_mojo(\"executethis\")" )
@$scriptContents.runFuncFromAnyScript("f:\\zzzz\\wdscript\\","mojo.js","hola_mojo(\"executethis\")" )                
    [0x0]            : hola mojo this is javascript 
    [0x1]            : hello mojo this is the argument you sent to me for execution I have executed your executethis
    [0x2]            : @$scriptContents.hola_mojo("executethis")
blabb
  • 8,674
  • 1
  • 18
  • 27
  • The one thing this doesn't do is get the script directory in there from the environment. I have to know where everything is for it to work. That wasn't an explicit requirement of the question, though. – mojo Aug 01 '19 at 18:23