Where's the call stack when debugging a content script?

Here I’m trying to debug an add-on content script which is doing something wrong on a specific web page. I can get the debugger going (which requires turning on badly documented settings). I can see the files in the debugger. I can set breakpoints. Execution stops at the breakpoints. The proper line in the code is boxed if I scroll to that line.

But there’s no call stack shown, ever. See picture. I can stop and start execution, and step forward, but no call stack. And, although the box showing the current line will move in the source window, if it moves out of the window the window does not scroll and there’s no indication of where execution is gone.

Yes, I have “remote debugging” turned on. FF 80.0-b8, dev version.

1 Like

Something is wrong :slight_smile:, it works fine in my Firefox 80.
Try to use web-ext. It will run fresh Firefox with empty default profile. See if it will work there:

npm i -g web-ext
cd /my_extension_dir
web-ext run --firefox=firefoxdeveloperedition --pref=browser.ctrlTab.recentlyUsedOrder=false --pref=devtools.webconsole.timestampMessages=true --pref=signon.rememberSignons=true --start-url about:debugging#/runtime/this-firefox

web-ext won’t build on Ubuntu 18.04 LTS. Node.js version problems.
Besides, that’s just complicating the problem.

I’m already using a downloaded version of the developer Firefox with a nearly blank profile.

So actually later today I’ve been debugging a background script and suddenly there was no Call Stack :smiley:. It works most of the times, but it’s far from perfect I guess…

But from my own experience I can suggest you to:

  • open Browser Console (Ctrl + Shift + J) if you are looking for errors in your content script (there is bug)
  • when debugging gets broken or makes no sense, restart browser :smiley:
  • if debugging is complex and keeps breaking, better to open Chrome (it’s a last resort but it’s so much more reliable)

OK, you see the call stack disappearing, too. So there’s a real bug.

(I know how to find ordinary errors. I’m looking for a more subtle bug. This is an old, working add-on which needs some work to deal with a change in a page it’s working on, and for the first time I really need to step through with the debugger and see why the content script and the page content don’t get along.)

1 Like

Maybe few more tips:

  • there is a debugger statement
  • you can also print stack with Error().stack
  • you can print “clickable” stack, just call (don’t await) this async function:
async function printStack() {
  throw 'print stack';    // throwing in async fn will not break caller YET it allows stack examination in Dev console with clickable files!

But yeah, I can feel you pain :slight_smile:. When there are some crazy bugs it’s always a huge help to have a strong debugging tool.

Debugger crashed on content script.

Sometimes I can see the call stack, as above. Sometimes it doesn’t appear. Sometimes it goes away while stepping. I can set breakpoints and get stops, and can step from there, but no call stack.

Is this debugger just broken, or what?

1 Like

I’ve seen the crash many times. Actually I’ve just managed to reproduce it :smiley: just now. It’s when you pause on some line (in content script) and then your extension gets reloaded.

I tried the WebExtension in Chromium. Works perfectly over there.

What I’m actually doing is working on my Ad Limiter, which you can get from the Mozillla add-on store. It gets ratings for sites (I have a server for that) and displays them on search results. My usual test is to search for “Hacker news”, a non ad-heavy topic. On Bing search result pages, the first search result often disappears. That’s not supposed to happen.

In the debugger, I see the page being updated properly, and a green checkmark appears next to the search result. That’s done internally in the DOM by wrapping the search result in a DIV with the checkmark icon and some other stuff, followed by the search result content. I see those DOM changes going in fine. The page displays accordingly. Then, after the add-on code has finished, something deletes the first search result, everything inside the LI. The page updates and that content disappears. It’s gone from the DOM.

So I’m trying to find what’s doing that. Something in Bing’s code? Something in my code? If I could step through in the debugger, this would be easy to find. I have console.log calls all through my code, and with them enabled, there’s nothing which seems likely to be the cause of the problem. There’s a thing for deleting some ads, but I have that turned off, logging for it turned on, and a debugger breakpoint to catch control going through there. Not happening.

This is starting to look like some obscure Firefox bug, especially since it doesn’t appear under Chrome. Any ideas?

Latest comment on the debugger bug is to try some new debugger in Nightly Firefox that might work.

As a side note, I’ve noticed problems manipulating the DOM of Bing results in my userscript. Stuff sometimes vanishes for no apparent reason. My guess is that Bing has some code that detects and removes unrecognized/alien tags.


1 Like

You can actually debug DOM changes directly! Just right click on some element and from context menu click “Break on” / … . I think it works in both Firefox and Chrome. I’ve used it in Firefox some time ago when I needed to see what script was modifying some element.


That helped. I found the code in the Bing search result page that does a removeChild and is messing up my add-on’s page changes. The page sets a mutation observer to check if something else modifies the page. If there’s already a mutation observer (which there is, because the add-on set one), it logs a message of “CI.AdPrevention”, which presumably is sent to Bing HQ somewhere. I also found the removeChild that’s messing things up. Now I have to figure out what Bing is really trying to do.

But that’s it. It’s apparently something Bing put in to prevent people from messing with their search results.

Here’s part of Bing’s code:

function r(t) {
		var i = window.location.pathname,
		try {
			window.MutationObserver != undefined && (typeof MutationObserver != "function" || MutationObserver.toString().indexOf("[native code]") < 0) ? sj_log("CI.AdPrevention", "MutationObserver overrided", "true") : (window.MutationObserver || window.WebKitMutationObserver) && typeof MutationObserver == "function" ? i && (i.toUpperCase() === "/SEARCH" || i.toUpperCase() === "/" || i.toUpperCase() === "/MAPS" || i.toUpperCase() === "/MAPSPREVIEW") && (r = new MutationObserver(function (t) {
				var f, r, e, i;
				if (t)
					for (f = 0; f < t.length; f++)
						if (r = t[f].addedNodes, r && r.length)
							for (e = 0; e < r.length; e++) {
								i = r[e];
								switch (i.tagName) {
									case "IFRAME":
									case "IMG":
									case "SCRIPT":
									case "LINK":
									case "DIV":
									case "LI":
									case "OBJECT":
										i.type && i.type.indexOf("flash") >= 0 && n(i, "RN", i.outerHTML.substr(0, u));
									case "CENTER":
										n(i, "RN", i.outerHTML.substr(0, u));
			}), r.observe(t, {
				childList: !0,
				subtree: !0
			})) : sj_log("CI.AdPrevention", "MutationObserver not available", "true")
		} catch (f) {
			sj_log("CI.AdPrevention", "error_creating_dom_observer", f.name)
1 Like

Actually it’s just a feature detection - it’s checking if MutationObserver API is available in your browser.

Your content script lives in it’s own “bubble” and web-page can’t see it’s variables.
Read this part for more info:

From the code that you posted is seems that the observer reacts only to these elements: "IFRAME", "IMG", "SCRIPT", "LINK", "DIV", "LI", "OBJECT", "CENTER".
So all you have to do is avoid these and you should be fine :slight_smile:.

And if you don’t feel like doing compromises, you should be fine if you use Shadow DOM API.

Yes. I now have my add-on fixed. Instead of inserting <DIV> tags, I have it insert <SPAN> tags with “display: block;”. That does the same thing as a DIV. The anti ad blocker code in Bing search result pages does not try to modify the SPAN tags, and so it all works. Technically, this is not correct, because I now have a SPAN enclosing a block element, but at the DOM level, it seems that DIV and SPAN only differ in their “display” attribute.

If the anti ad blocker code gets more aggressive I may have to go to a shadow DOM, but it’s not necessary yet.

I am running Firefox 118.0.2 on Ubuntu 22.04 LTS. A function is being called with an invalid parameter value. But because THERE IS NO CALL STACK displayed by the debugger how the hell am I supposed to figure out where my function is being called from?