console.logのことを思い出す

FirebugがunsafeWindowにconsoleを設定してるのだった。
コードは脆弱性、全てのサイトでGM_xmlhttpRequestを使う、解説と回避 - 実用でnanto_viさんが

対応策として考えられるのは、関数宣言・変数宣言を使わず、明示的に this をつけることにより、すべての値をsandbox オブジェクトのプロパティとして扱うことです。

といわれているように、全部thisがつけられている。コメントにもそのことが書かれている。

function FirebugConsole(context, win)
{
    this.firebug = Firebug.version;

    // We store these functions as closures so that they can access the context privately,
    // because it would be insecure to store context as a property of window.console and
    // and therefore expose it to web pages.

    this.log = function()
    {
        logFormatted(arguments, "log");
    };

そしてFirebugはこのwindow.consoleを設定するタイミングの実装に注意を払っている。

    watchWindow: function(context, win)
    {
        // XXXjoe Move this to Firebug.Console
        if (!win.console) {
            win.console = new FirebugConsole(context, win);
        }

というコードで値を入れてるので(winはGMでいうunsafeWindow)、当然window.console のsetterに細工をされたら? ということになる。
watchWindowが呼ばれるタイミングは

var FrameProgressListener = extend(BaseProgressListener,
{
    onStateChange: function(progress, request, flag, status)
    {
        // We need to get the hook in as soon as the new DOMWindow is created, but before
        // it starts executing any scripts in the page.  After lengthy analysis, it seems
        // that the start of these "dummy" requests is the only state that works.
        if (flag & STATE_IS_REQUEST && flag & STATE_START)
        {
            if (safeGetName(request) == dummyURI)
            {
                // Another weird edge case here - when opening a new tab with about:blank,
                // "unload" is dispatched to the document, but onLocationChange is not called
                // again, so we have to call watchTopWindow here
                var win = progress.DOMWindow;
                if (win.parent == win && win.location.href == "about:blank")
                    TabWatcher.watchTopWindow(win, null);

                TabWatcher.watchWindow(win);
            }
        }

        // Later I discovered that XHTML documents don't dispatch the dummy requests, so this
        // is our best shot here at hooking them.
        if (flag & STATE_IS_DOCUMENT && flag & STATE_TRANSFERRING)
            TabWatcher.watchWindow(progress.DOMWindow);
    }
});

に書いてあるとおり、DOMWindowが生成された後でかつjavascriptの実行が行われる前というタイミング。これならwindowはあるけどconsoleに細工をされる心配がないので安心してunsafeWindow.consoleに代入できる。

ちなみにこのタイミング、自分で書くと簡単には取れないかんじでした。
でも拡張機能からならTabWatcher.watchWindow()で、じぶんの関数をFirebugからよんでもらうことができます。wiiremocomのwindow.wiiremocomはそうして設定しました。デバッグとか楽になると思います。
今気づいたけど、これ使うとほんとにextensionのコードとして書かないところだけをちょこっと書いて、後はふつうのhtmlファイルで開発していくとかできそう。便利かわかんないけど。