trbr
Version:
TraceBreaker is a simple tool to decode and analyze ESP backtraces
2 lines • 30.9 kB
JavaScript
import{createRequire as t}from"node:module";var e={d:(t,r)=>{for(var n in r)e.o(r,n)&&!e.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:r[n]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e)},r={};e.d(r,{lc:()=>n,tI:()=>tt,jb:()=>j,D4:()=>rt,Br:()=>Z,bU:()=>$,xR:()=>C,M4:()=>et,aV:()=>ot,jp:()=>st,Hx:()=>P,mv:()=>R,vl:()=>gt});class n extends Error{constructor(){super("User abort"),this.name="AbortError",this.code="ABORT_ERR"}}const o=(new AbortController).signal,s=t(import.meta.url)("node:fs/promises"),i=t(import.meta.url)("node:os"),a=t(import.meta.url)("node:path"),c=t(import.meta.url)("node:stream/promises"),d=t(import.meta.url)("node:child_process");function l(t){return t.split(/\r?\n/).map((t=>t.trim())).filter(Boolean).map((t=>function(t){const e=[/#\d+\s+(0x[0-9a-f]+)\s+in\s+([^(]+\((?:"(?:\\.|[^"\\])*"|[^()])*?\))\s+at\s+(.+):(\d+)/i,/(0x[0-9a-f]+)\s+in\s+([^(]+(?:\([^()]*\))?)\s+at\s+(.+):(\d+)/i,/(?:#\d+\s+)?(0x[0-9a-f]+)\s+in\s+([^(]+(?:\([^()]*\))?)\s+at\s+(\?+):(\?+)/i,/(0x[0-9a-f]+)\s+is\s+in\s+([^(]+(?:\([^()]*\))?)\s+\((.+):(\d+)\)/i,/(0x[0-9a-f]+)\s+is\s+in\s+([^(]+(?:\([^()]*\))?)\s+\(([^():]+)\)/i,/(0x[0-9a-f]+)\s+is\s+at\s+(.+):(\d+)/i,/(?:#\d+\s+)?([^(]+(?:\([^()]*\))?)\s+at\s+(.+):(\d+)/];for(const[r,n]of e.entries()){const e=t.match(n);if(e){if(0===r||1===r){const[,t,r,n,o]=e;return u({regAddr:t,method:r,file:n,lineNumber:o})}if(2===r){const[,t,r,n,o]=e;return u({regAddr:t,method:r,file:n,lineNumber:o})}if(3===r){const[,t,r,n,o]=e;return u({regAddr:t,method:r,file:n,lineNumber:o})}if(4===r){const[,t,r,n]=e;return u({regAddr:t,method:r,file:n,lineNumber:"??"})}if(5===r){const[,t,r,n]=e;return u({regAddr:t,method:"??",file:r,lineNumber:n})}if(6===r){const[,t,r,n]=e;return u({regAddr:"??",method:t,file:r,lineNumber:n})}}}const r=t.match(/(?:#\d+\s+)?(0x[0-9a-f]+)\s+(?:is\s+in|in)\s+([^(]+(?:\([^()]*\))?)/i);if(r){const[,t,e]=r;return u({regAddr:t,method:e.trim(),file:"??",lineNumber:"??"})}}(t))).filter(ot||st)}function u(t){const{file:e,lineNumber:r,method:n,regAddr:o}=t,s=function(t){const e=t.match(/^([^(]+)\s*\((.*)\)$/s);if(!e)return{name:t.trim(),args:[]};const[,r,n]=e,o=n.match(/(?:[^,"']+|"[^"]*"|'[^']*')+/g)?.map((t=>{const e=t.split("=");if(2===e.length){const[t,r]=e.map((t=>t.trim()));return{name:t,value:r}}return{name:t.trim()}}))||[];return{name:r.trim(),args:o}}(n),i=e&&""!==e&&"??"!==e,a=r&&""!==r&&"??"!==r;if(i||a){const t={regAddr:o,method:s.name,file:i?e:"??",lineNumber:a?r:"??"};return s.args&&s.args.length>0&&Object.assign(t,{args:s.args}),t}const c=s.name&&""!==s.name&&"??"!==s.name&&"?? ()"!==s.name;return!a&&c?{regAddr:o,lineNumber:s.name}:{regAddr:o,lineNumber:r||"??"}}function f(t=0){return`0x${t.toString(16).padStart(8,"0")}`}const h="(gdb)";class p{constructor({toolPath:t,elfPath:e},r={}){this.toolPath=t,this.elfPath=e,this.error=null,this.didExecuteFirstCommand=!1,this.gdb=(0,d.spawn)(t,[e],{stdio:"pipe",signal:r.signal}),this.buffer="",this.queue=[],this.current=null,this.gdb.stdout.on("data",(t=>this._onData(t))),this.gdb.stderr.on("data",(t=>this._onData(t))),this.gdb.on("error",(t=>this.current?.reject(t))),this.gdb.on("exit",((t,e)=>{0!==t&&"SIGTERM"!==e&&console.warn(`GDB exited with code ${t} or signal ${e}`)}))}_onData(t){if(this.buffer+=t.toString(),!this.current)return;const e=this.buffer.indexOf(h);if(-1===e)return;const r=this.buffer.slice(0,e);this.buffer=this.buffer.slice(e+5);const{resolve:n}=this.current;this.current=null,n(r),this._processQueue()}_processQueue(){const t=this.queue.shift();if(this.current||!t)return;const{cmd:e,resolve:r,reject:n}=t;this.current={resolve:r,reject:n},this.gdb.stdin.write(e+"\n")}start(){return new Promise(((t,e)=>{const r=r=>{if(!this.didExecuteFirstCommand&&this.buffer.includes("No such file or directory"))return void(this.error||(this.error=new Error(`The ELF file does not exist or is not readable: ${this.elfPath}`),e(this.error)));if(!this.didExecuteFirstCommand&&(this.buffer.includes("not in executable format")||this.buffer.includes("file format not recognized")))return void(this.error||(this.error=new Error(`The ELF file is not in executable format: ${this.elfPath}`),e(this.error)));this.buffer+=r.toString();const n=this.buffer.indexOf(h);-1!==n&&(this.buffer=this.buffer.slice(n+5),t(""))};this.gdb.on("error",(t=>{let r=t;t instanceof Error&&"code"in t&&"ENOENT"===t.code&&(r=new Error(`GDB tool not found at ${this.toolPath}`)),e(r)})),this.gdb.stdout.on("data",r),this.gdb.stderr.on("data",r)}))}async exec(t){if(this.error)return this.close(),Promise.reject(this.error);const e=await new Promise(((e,r)=>{this.queue.push({cmd:t,resolve:e,reject:r}),this._processQueue()}));return this.didExecuteFirstCommand=!0,e}async close(){this.gdb.killed||(this.gdb.stdin.end(),this.gdb.kill("SIGTERM"),"number"!=typeof this.gdb.exitCode&&await new Promise((t=>this.gdb.once("exit",t))))}}async function g({elfPath:t,toolPath:e},r,n={}){const o=function(t){const e=new Set;for(const r of t){let t;"object"==typeof r?t=r.addr:"number"==typeof r&&(t=r),void 0===t||e.has(t)||e.add(t)}return Array.from(e.values())}(r);if(!o.length)throw new Error("No register addresses found to decode");const s=new Map,i=new p({elfPath:t,toolPath:e},n);try{await i.start(),await i.exec("set pagination off"),await i.exec("set listsize 1");for(const t of o){const e=f(t);let r=l(await i.exec(`list *${e}`)),n=r.find(st);n||(r=l(await i.exec(`info line *${e}`)),n=r.find(st)),s.set(t,{addr:t,location:n??{regAddr:e,lineNumber:"??"}})}}finally{await i.close()}return r.map((t=>{const e="object"==typeof t?t.addr:t;return s.get(e)||{location:"??"}}))}class m{constructor(t,e,r={}){this.cp=d.spawn(t,e,{stdio:"pipe",signal:r.signal}),this.error=void 0,this.commandQueue=[],this.signal=r.signal,this.signal&&this.signal.addEventListener("abort",(()=>{const t=new n;this.error=t,this.commandQueue.forEach((e=>e.reject(t))),this.commandQueue=[]})),this.stdoutBuffer="",this.cp.stdout.on("data",(t=>this._onData(t))),this.cp.stderr.on("data",(t=>this._onData(t))),this.cp.on("error",(t=>{this.error=t,this.commandQueue.forEach((e=>e.reject(t))),this.commandQueue=[]}))}sendCommand(t){return this.error?Promise.reject(this.error):new Promise(((e,r)=>{const n={resolve:e,reject:r};this.commandQueue.push(n),this.cp.stdin.write(`${t}\n`)}))}_onData(t){if(this.error&&(this.commandQueue.forEach((t=>t.reject(this.error))),this.commandQueue=[]),this.stdoutBuffer+=t.toString(),/\(gdb\)\s*$/m.test(this.stdoutBuffer)){const t=this.stdoutBuffer;this.stdoutBuffer="";const e=this.commandQueue.shift();e?.resolve(t)}}close(){this.cp.stdin.end(),this.cp.kill()}async drainHandshake(){return new Promise(((t,e)=>{const r=n=>{if(this.error)return this.cp.stdout.off("data",r),void e(this.error);this.stdoutBuffer+=n.toString(),/\(gdb\)\s*$/m.test(this.stdoutBuffer)&&(this.cp.stdout.off("data",r),this.signal&&this.signal.removeEventListener("abort",o),this.stdoutBuffer="",t())},o=()=>{this.cp.stdout.off("data",r),this.signal?.removeEventListener("abort",o),e(new n)};this.cp.stdout.on("data",r),this.signal?.addEventListener("abort",o)}))}}function b(t){const e={},r=t.match(/(?:frame=\{[^}]*\},)?register-values=\[([^\]]*)\]/);if(r){const t=r[1],n=/\{number="(\d+)",value="(0x[a-fA-F0-9]+)"\}/g;for(const r of t.matchAll(n))e[r[1]]=r[2];return e}const n=t.split(/\r?\n/);for(const t of n){const r=t.match(/^~?"?(\w+)\s+(0x[a-fA-F0-9]+)\b/);if(r){const[,t,n]=r;e[t]=n}}return e}async function w(t,e,r={},n=!0){const{elfPath:o,toolPath:c}=t,{inputPath:d}=e,l=new m(c,["--interpreter=mi2","-c",d,o],r),u=[];try{await l.drainHandshake();const t=await l.sendCommand("-thread-info"),e=t.match(/current-thread-id="(\d+)"/),r=e?e[1]:null,n=function(t){const e=t.indexOf("threads=[");if(e<0)return;const r=t.indexOf("[",e);if(r<0)return;let n=0;for(let e=r;e<t.length;e++){const o=t[e];if("["===o)n++;else if("]"===o&&(n--,0===n))return t.substring(r+1,e)}}(t),o=[];if(n){const t=[];let e=0,r=-1;for(let o=0;o<n.length;o++){const s=n[o];"{"===s?(0===e&&(r=o),e++):"}"===s&&(e--,0===e&&r>=0&&t.push(n.slice(r,o+1)))}for(const e of t){const t=/id="([^"]+)"\s*,\s*target-id="process\s+(\d+)"/.exec(e);t&&o.push([t[1],t[2]])}}const s=o.map((([t])=>t)),i=Object.fromEntries(o.map((([t,e])=>[t,Number(e)])));for(const t of s){await l.sendCommand(`-thread-select ${t}`);const e=(await l.sendCommand("-data-list-register-names")).match(/register-names=\[(.*?)\]/),n=e?e[1].split(",").map((t=>t.trim().replace(/^"|"$/g,""))).map(((t,e)=>[e.toString(),t])).filter((([,t])=>!!t)):[],o=Object.fromEntries(n),s=b(await l.sendCommand("-data-list-register-values x")),a=Object.fromEntries(Object.entries(s).map((([t,e])=>[o[t],Number(e)])).filter((([t])=>!!t))),c=a.pc,d=await l.sendCommand("-stack-list-frames"),h=(await l.sendCommand("-stack-list-arguments --simple-values 0 100")).match(/stack-args=\[([\s\S]*)\]/);let p=[];if(h){const t=h[1].split(/},\s*frame=\{/).map(((t,e)=>0===e?t+"}":"frame={"+t+"}"));p=t.map((t=>{const e=t.match(/frame=\{([\s\S]*)\}/),r=e?e[1]:"",n={args:[]},o=r.match(/level="(\d+)"/);o&&(n.level=o[1]);const s=r.match(/args=\[([\s\S]*)\]/);if(s&&s[1].trim()){const t=s[1],e=/\{name="([^"]+)",type="([^"]+)",value="([^"]+)"\}/g;let r;for(;r=e.exec(t);)n.args.push({name:r[1],type:r[2],value:r[3]})}return n}))}else p=[];const g=[...d.matchAll(/frame=\{([^}]+)\}/g)].map((t=>{const e={};for(const r of t[1].split(",")){const[t,n]=r.split("=");e[t]=n?.startsWith('"')?n.slice(1,-1):n}return e})).map(((t,e)=>{const r=p[e]?.args||"";return{regAddr:t.addr,lineNumber:t.line??"??",...t.func&&t.file?{method:t.func,file:t.file,args:r}:{}}}));u.push({threadId:t,TCB:i[t],result:{faultInfo:{coreId:parseInt(t),programCounter:{addr:c,location:g[0]??{regAddr:f(c),lineNumber:"??"}},faultCode:void 0},regs:a,stacktraceLines:g},current:t===r})}}finally{l.close()}if(!u.length&&n){const r=await s.readFile(e.inputPath),n=await async function(t,e){const r=Buffer.from([127,69,76,70]),n=e.indexOf(r);if(-1!==n){const r=e.readUInt32LE(n+28),o=e.readUInt16LE(n+42),c=e.readUInt16LE(n+44),d=(()=>{let t=0;for(let s=0;s<c;s++){const i=n+r+s*o,a=e.readUInt32LE(i+4)+e.readUInt32LE(i+16);a>t&&(t=a)}return t})();if(e.length>=n+d){const r=e.subarray(n,n+d),o=await s.mkdtemp(a.join(i.tmpdir(),"trbr-")),c=a.join(o,"extracted.elf");await s.writeFile(c,r);try{return await w({...t},{inputPath:c},void 0,!1)}finally{await s.rm(o,{recursive:!0,force:!0}).catch((t=>console.warn("Failed to clean up temp dir:",t)))}}}}(t,r);if(n)return n}return u}const A={unsupportedTargetArch:t=>`Unsupported decode target: ${t}`};async function y(t,e=[],r={}){return new Promise(((n,o)=>{(0,d.execFile)(t,e,r,((t,e,r)=>{t?o(t):n({stdout:e.toString(),stderr:r.toString()})}))}))}async function C({arduinoCliPath:t,fqbn:e,arduinoCliConfigPath:r,additionalUrls:n},o){return R({fqbn:e,buildProperties:await I({arduinoCliPath:t,fqbn:e,additionalUrls:n,arduinoCliConfigPath:r},o)})}async function I({arduinoCliPath:t,fqbn:e,arduinoCliConfigPath:r,additionalUrls:n},o){const{stdout:s}=await async function({fqbn:t,arduinoCliPath:e,arduinoCliConfigPath:r,additionalUrls:n,signal:o}){const s=["board","details","-b",t.toString(),"--format","json"];return r&&s.push("--config-file",r),n&&s.push("--additional-urls",n),y(e,s,{signal:o})}({arduinoCliPath:t,fqbn:e,arduinoCliConfigPath:r,additionalUrls:n,signal:o?.signal}),{build_properties:i}=JSON.parse(s);return i.reduce(((t,e)=>{const r=function(t){const e=t.split(F);if(e.length<2)return void console.warn(`Could not parse build property: ${t}.`);const[r,...n]=e;return r?[r,n.join(F)]:void console.warn(`Could not determine property key from raw: ${t}.`)}(e);if(r){const[e,n]=r;t[e]=n}return t}),{})}const v=["esp32c2","esp32c3","esp32c6","esp32h2","esp32h4","esp32p4"],S="xtensa";function P(t){return"string"==typeof t&&v.includes(t)}const E="build.mcu";function $({buildProperties:t}){const e=t[E];return P(e)?e:S}const x="esp32",B=new Set([x,"esp8266"]),L="xtensa",N="lx106",O="build.tarch",k="build.target";async function R({fqbn:t,buildProperties:e}){const{arch:r}=t;if(!B.has(r))throw new Error(`Unsupported board architecture: '${t}'`);let n=L,o=N;r===x&&(n=e[O]??L,o=e[k]??N);const i=`${n}-${o}-elf`,c=`${n}-esp-elf-gdb`,d=`${i}-gdb${"win32"===process.platform?".exe":""}`;async function l(t){const r=e[t];if(r){const t=a.join(r,"bin",d);try{return await s.access(t),t}catch{}}}const u=`tools.${c}.path`,f=`tools.${i}-gcc.path`,h=(await Promise.all([l(`runtime.${u}`),l(`runtime.${f}`),l(u),l(f)])).find((t=>t));if(!h)throw new Error(`Could not find GDB tool for '${t}'`);return h}const F="=";function T(t){return"coredumpMode"in t&&Boolean(t.coredumpMode)}async function j(t){let e,r;if(function(t){return"toolPath"in t&&"string"==typeof t.toolPath}(t))e=t.toolPath,r=t.targetArch??S;else if(function(t){return"buildProperties"in t&&"object"==typeof t.buildProperties}(t))e=await R(t),r=$(t);else{if(!function(t){return"arduinoCliPath"in t&&"string"==typeof t.arduinoCliPath}(t))throw new Error(`Unexpected create decode params input: ${JSON.stringify(t)}`);{const n=await I(t);e=await R({fqbn:t.fqbn,buildProperties:n}),r=$({buildProperties:n})}}const n={elfPath:t.elfPath,toolPath:e,targetArch:r};return T(t)?{...n,coredumpMode:!0}:n}const M=t(import.meta.url)("node:net"),D=["X0","RA","SP","GP","TP","T0","T1","T2","S0/FP","S1","A0","A1","A2","A3","A4","A5","A6","A7","S2","S3","S4","S5","S6","S7","S8","S9","S10","S11","T3","T4","T5","T6","MEPC"],_={esp32c2:H,esp32c3:H,esp32c6:H,esp32h2:H,esp32h4:H,esp32p4:H},U={esp32c2:D,esp32c3:D,esp32c6:D,esp32h2:D,esp32h4:D,esp32p4:D};function q({input:t,target:e}){const{regDumps:r,stackDump:n,programCounter:o,faultAddr:s,faultCode:i}=function({input:t,target:e}){const r=t.split(/\r?\n|\r/),n=[],o=[];let s,i,a,c=!1,d=0;const l=function(t){const e=U[t];if(!e)throw new Error(`Unsupported target: ${t}`);return t=>e.includes(t)}(e);return r.forEach((t=>{if(t.startsWith("Core")){const e=t.match(/^Core\s+(\d+)\s+register dump:/);e&&(s={coreId:parseInt(e[1],10),regs:{}},n.push(s))}else if(s&&!c){const e=t.matchAll(/([A-Z_0-9/]+)\s*:\s*(0x[0-9a-fA-F]+)/g);for(const t of e){const e=t[1],r=parseInt(t[2],16);r&&l(e)?(s.regs[e]=r,"MEPC"===e&&(d=r)):"MCAUSE"===e?i=r:"MTVAL"===e&&(a=r)}"Stack memory:"===t.trim()&&(c=!0)}else if(c){const e=t.match(/^([0-9a-fA-F]+):\s*((?:0x[0-9a-fA-F]+\s*)+)/);if(e){const t=parseInt(e[1],16),r=e[2].trim().split(/\s+/).map((t=>parseInt(t,16)));o.push({baseAddr:t,data:r})}}})),{regDumps:n,stackDump:o,faultCode:i,faultAddr:a,programCounter:d}}({input:t,target:e});if(0===r.length)throw new Error("No register dumps found");if(r.length>1)throw new Error("Handling of multi-core register dumps not implemented");const{coreId:a,regs:c}=r[0],{stackBaseAddr:d,stackData:l}=function({stackDump:t}){let e=0,r=0,n=0,o=Buffer.alloc(0);return t.forEach((t=>{const s=r;if(r=t.baseAddr,0===e)e=r;else if(r!==s+n)throw new Error("Invalid base address");const i=Buffer.concat(t.data.map((t=>Buffer.from(t.toString(16).padStart(8,"0"),"hex"))));n=i.length,o=Buffer.concat([o,i])})),{stackBaseAddr:e,stackData:o}}({stackDump:n});return{coreId:a,programCounter:o,faultAddr:s,faultCode:i,regs:c,stackBaseAddr:d,stackData:l,target:e}}class G{constructor(t){this.panicInfo=t.panicInfo,this.regList=U[t.panicInfo.target],this.debug=t.debug??(()=>{})}async start(t={}){if(this.server)throw new Error("Server already started");const{signal:e=o}=t,r=M.createServer();this.server=r,await new Promise(((t,o)=>{const s=()=>{this.debug("User abort"),o(new n),this.close()};e.aborted?s():(e.addEventListener("abort",s),r.on("listening",(()=>{e.removeEventListener("abort",s),t(void 0)})),r.listen(0))}));const s=r.address();if(!s)throw this.close(),new Error("Failed to start server");if("string"==typeof s)throw this.close(),new Error(`Expected an address info object. Got a string: ${s}`);return r.on("connection",(t=>{t.on("data",(e=>{const r=e.toString();if(r.startsWith("-"))return this.debug(`Invalid command: ${r}`),t.write("-"),void t.end();r.length>3&&"#"===r.slice(-3,-2)&&(this.debug(`Command: ${r}`),this._handleCommand(r,t))}))})),s}close(){this.server?.close(),this.server=void 0}_handleCommand(t,e){t.startsWith("+")&&(t=t.slice(1));const r=t.slice(1,-3);if(e.write("+"),this.debug(`Raw buffer (length ${t.length}): ${JSON.stringify(t)}`),this.debug(`Got command: ${r}`),"?"===r)this.debug("Responding with: T05"),this._respond("T05",e);else if(r.startsWith("Hg")||r.startsWith("Hc"))this.debug("Responding with: OK"),this._respond("OK",e);else if("qfThreadInfo"===r)this.debug("Responding with: m1"),this._respond("m1",e);else if("qC"===r)this.debug("Responding with: QC1"),this._respond("QC1",e);else if("g"===r)this._respondRegs(e);else if(r.startsWith("m")){const[t,n]=r.slice(1).split(",").map((t=>parseInt(t,16)));this._respondMem(t,n,e)}else r.startsWith("vKill")||"k"===r?(this.debug("Responding with: OK"),this._respond("OK",e),e.end()):(this.debug("Responding with: (empty)"),this._respond("",e))}_respond(t,e){const r=`$${t}#${(255&Buffer.from(t,"ascii").reduce(((t,e)=>t+e),0)).toString(16).padStart(2,"0")}`;e.write(r),this.debug(`Wrote: ${r}`)}_respondRegs(t){let e="";for(const t of this.regList){const r=this.panicInfo.regs[t]||0,n=Buffer.alloc(4);n.writeUInt32LE(r),e+=n.toString("hex")}this.debug(`Register values: ${this.regList.map((t=>`${t}=${f(this.panicInfo.regs[t]||0)}`)).join(", ")}`),this.debug(`Register response: ${e}`),this._respond(e,t)}_respondMem(t,e,r){const n=this.panicInfo.stackBaseAddr,o=this.panicInfo.stackData,s=o.length,i=n+s,a=t=>n<=t&&t<i;let c="";for(let r=t;r<t+e;r++)a(r)?c+=o[r-n].toString(16).padStart(2,"0"):c+="00";this.debug(`Memory read request from 0x${t.toString(16)} for ${e} bytes`),this.debug(`Responding with memory: ${c}`),this._respond(c,r)}}const Q=[{code:0,description:"Instruction address misaligned"},{code:1,description:"Instruction access fault"},{code:2,description:"Illegal instruction"},{code:3,description:"Breakpoint"},{code:4,description:"Load address misaligned"},{code:5,description:"Load access fault"},{code:6,description:"Store/AMO address misaligned"},{code:7,description:"Store/AMO access fault"},{code:8,description:"Environment call from U-mode"},{code:9,description:"Environment call from S-mode"},{code:11,description:"Environment call from M-mode"},{code:12,description:"Instruction page fault"},{code:13,description:"Load page fault"},{code:15,description:"Store/AMO page fault"}];async function W(t,e,r={}){const{elfPath:n,toolPath:o}=t;let s;try{const{signal:t,debug:i}=r,a=new G({panicInfo:e,debug:i}),{port:c}=await a.start({signal:t});s=a;const d=function(t,e){return["--batch","-n",t,"-ex",`target remote :${e}`,"-ex","bt"]}(n,c),{stdout:l}=await y(o,d,{signal:t});return l}finally{s?.close()}}async function H(t,e,r){const n=t.targetArch;if(!P(n))throw new Error(`Unsupported target: ${n}`);let o;if(o="string"==typeof e?q({input:e,target:n}):e,"backtraceAddrs"in o)throw new Error("Unexpectedly received a panic info with backtrace addresses for RISC-V");const[s,[i,a]]=await Promise.all([W(t,o,r),g(t,[o.programCounter,o.faultAddr],r)]);return function(t,e,r,n){const o=Q.find((e=>e.code===t.faultCode)),s=l(n);return{faultInfo:{coreId:t.coreId,programCounter:e,faultAddr:r,faultCode:t.faultCode,faultMessage:o?o.description:void 0},regs:t.regs,stacktraceLines:s,allocInfo:void 0}}(o,i,a,s)}const J="reserved",z=["Illegal instruction","SYSCALL instruction","InstructionFetchError: Processor internal physical address or data error during instruction fetch","LoadStoreError: Processor internal physical address or data error during load or store","Level1Interrupt: Level-1 interrupt as indicated by set level-1 bits in the INTERRUPT register","Alloca: MOVSP instruction, if caller's registers are not in the register file","IntegerDivideByZero: QUOS, QUOU, REMS, or REMU divisor operand is zero",J,"Privileged: Attempt to execute a privileged operation when CRING ? 0","LoadStoreAlignmentCause: Load or store to an unaligned address",J,J,"InstrPIFDataError: PIF data error during instruction fetch","LoadStorePIFDataError: Synchronous PIF data error during LoadStore access","InstrPIFAddrError: PIF address error during instruction fetch","LoadStorePIFAddrError: Synchronous PIF address error during LoadStore access","InstTLBMiss: Error during Instruction TLB refill","InstTLBMultiHit: Multiple instruction TLB entries matched","InstFetchPrivilege: An instruction fetch referenced a virtual address at a ring level less than CRING",J,"InstFetchProhibited: An instruction fetch referenced a page mapped with an attribute that does not permit instruction fetch",J,J,J,"LoadStoreTLBMiss: Error during TLB refill for a load or store","LoadStoreTLBMultiHit: Multiple TLB entries matched for a load or store","LoadStorePrivilege: A load or store referenced a virtual address at a ring level less than CRING",J,"LoadProhibited: A load referenced a page mapped with an attribute that does not permit loads","StoreProhibited: A store referenced a page mapped with an attribute that does not permit stores"];function V(t){if(!t)return;const e=parseInt(ot(t)?t.regAddr:t??"0",16);return isNaN(e)?void 0:e}function K(t){return null!==t&&"object"==typeof t&&"inputPath"in t&&"string"==typeof t.inputPath}function Y(t){return null!==t&&"object"==typeof t&&"inputStream"in t&&t.inputStream instanceof require("stream").Readable}const Z="xtensa",X={[Z]:async function(t,e,r){let n;if("string"==typeof e?(n=function(t){const e=t.split(/\r?\n|\r/),r={};let n=0;const o=[],s=t.match(/Guru Meditation Error: Core\s+(\d+)/);s&&(n=parseInt(s[1],10));const i=/([A-Z]+[0-9]*)\s*:\s*(0x[0-9a-fA-F]+)/g;for(const t of e){for(const e of t.matchAll(i)){const[,t,n]=e,o=parseInt(n,16);Number.isNaN(o)||(r[t]=o)}if(t.startsWith("Backtrace:")){const e=Array.from(t.matchAll(/0x[0-9a-fA-F]{8}/g));for(const t of e){const e=parseInt(t[0],16);Number.isNaN(e)||o.push(e)}}}return{coreId:n,regs:r,backtraceAddrs:o,faultCode:r.EXCCAUSE,faultAddr:r.EXCVADDR,programCounter:r.PC}}(e),Object.keys(n.regs).length||n.backtraceAddrs.length||(n=function(t){const e=t.split(/\r?\n|\r/),r={},n=[];let o,s;const i=t.match(/Exception\s+\((\d+)\)/);i&&(o=parseInt(i[1],10));for(const t of e){const e=t.matchAll(/(epc\d+|excvaddr|depc)=(0x[0-9a-fA-F]{8})/g);for(const t of e){const[,e,n]=t;r[e.toUpperCase()]=parseInt(n,16),"excvaddr"===e.toLowerCase()&&(s=parseInt(n,16))}const o=t.match(/^\s*[0-9a-f]{8}:\s+((?:[0-9a-f]{8}\s*)+)/i);if(o){const t=o[1].trim().split(/\s+/);for(const e of t){const t=parseInt(e,16);!Number.isNaN(t)&&1073741824&t&&n.push(t)}}}return{coreId:0,regs:r,backtraceAddrs:n,faultCode:o,faultAddr:s,programCounter:r.EPC1}}(e))):n=e,"stackBaseAddr"in n)throw console.error("input contains stackBaseAddr",JSON.stringify(n)),new Error("panicInfo must not contain stackBaseAddr");const[o,s,...i]=await g(t,[n.programCounter,n.faultAddr,...n.backtraceAddrs??[]],r);let a;return n.faultCode&&(a=z[n.faultCode]),{faultInfo:{coreId:n.coreId,programCounter:o,faultAddr:s,faultCode:n.faultCode,faultMessage:a},regs:n.regs,stacktraceLines:i.map((({location:t})=>t)).filter(ot),allocInfo:void 0}},..._},tt=Object.keys(X);function et(t){return"string"==typeof t&&t in X}async function rt(t,e,r={debug:()=>{},signal:(new AbortController).signal}){const o=[];try{if(T(t)){let n;if(K(e))n=e.inputPath;else if(Y(e)){const t=await s.mkdtemp(a.join(i.tmpdir(),"trbr-"));n=a.join(t,"coredump.elf"),o.push((async()=>{try{await s.rm(t,{recursive:!0,force:!0})}catch(t){console.error("Failed to delete temporary coredump directory:",t)}}));const r=await s.open(n,"w");let d;try{d=r.createWriteStream(),await(0,c.pipeline)(e.inputStream,d)}finally{Promise.allSettled([r.close(),new Promise(((t,e)=>d?.close((r=>{r?e(r):t(void 0)}))))]).then((t=>t.forEach((t=>{"rejected"===t.status&&console.error("Failed to close stream:",t.reason)}))))}}if(!n)throw new Error(`Could not determine coredump path from input: ${JSON.stringify(e)}`);return(await w(t,{inputPath:n},r)).map((t=>({...t,...nt(t.result)})))}const{targetArch:d}=t,l=X[d];if(!l)throw new Error(A.unsupportedTargetArch(d));let u;if("string"==typeof e)u=e;else if(K(e))u=await s.readFile(e.inputPath,"utf8");else if(Y(e)){u="";for await(const t of e.inputStream)u=t.toString()}else u=e;const f=nt(await l(t,u,r));if(r.signal?.aborted)throw new n;return f}catch(t){if(t instanceof Error&&"code"in t&&"ABORT_ERR"===t.code)throw new n;throw t}finally{for(const t of o)try{await t()}catch(t){console.error("Failed to dispose resource:",t)}}}function nt(t){let e=function(t){return{...t,stacktraceLines:t.stacktraceLines.filter((t=>!ot(t)||"??"!==t.lineNumber||"0xfeefeffe"!==t.regAddr.toLowerCase()))}}(function(t){return{...t,faultInfo:t.faultInfo?{...t.faultInfo,programCounter:it(t.faultInfo.programCounter),faultAddr:it(t.faultInfo.faultAddr)}:void 0,stacktraceLines:t.stacktraceLines.map(it),allocInfo:t.allocInfo?{...t.allocInfo,allocAddr:it(t.allocInfo.allocAddr)}:void 0}}(t));e=function(t){return{...t,stacktraceLines:t.stacktraceLines.reduce(((t,e,r,n)=>{const o=n[r-1];return o&&function(t,e){if(!st(e))return!1;const r=V(e.regAddr),n=V(t.regAddr);if(void 0===n||void 0===r)return!1;const o=n>>>28==3,s=r>>>28==4;return"??"===t.lineNumber&&o&&s}(e,o)?t:[...t,e]}),[])}}(e);const r=function(t){if(t.faultInfo&&ot(t.faultInfo.faultAddr?.location)&&"??"===t.faultInfo.faultAddr.location.lineNumber&&!t.faultInfo.faultAddr.addr){const e=JSON.parse(JSON.stringify(t));return delete e.faultInfo.faultAddr,e}return t}(e),n=function(t){return{...t,stacktraceLines:t.stacktraceLines.reduce(((t,e,r)=>{const n=t[r-1];return!n||(s=e,st(o=n)&&!st(s)||!st(o)&&st(s)||(st(o)&&st(s)?o.regAddr!==s.regAddr||o.lineNumber!==s.lineNumber||o.file!==s.file||o.method!==s.method:o.regAddr!==s.regAddr||o.lineNumber!==s.lineNumber))?[...t,e]:t;var o,s}),[])}}(r);return n}function ot(t){return null!==t&&"object"==typeof t&&"regAddr"in t&&"string"==typeof t.regAddr&&"lineNumber"in t&&"string"==typeof t.lineNumber}function st(t){return ot(t)&&"file"in t&&"string"==typeof t.file&&"method"in t&&"string"==typeof t.method}function it(t){if(!t)return t;if(null!==(e=t)&&"object"==typeof e&&"addr"in e&&("number"==typeof e.addr||void 0===e.addr)&&"location"in e&&("string"==typeof e.location||ot(e.location)||st(e.location))){const e=t.location;if(st(e)){const r=JSON.parse(JSON.stringify(t));return r.location.file=at(e.file),r}}var e;if(st(t)){const e=JSON.parse(JSON.stringify(t));return e.file=at(t.file),e}return t}function at(t){return"win32"===process.platform&&/^[a-zA-Z]:\\/.test(t)?t.replace(/\//g,"\\"):t}var ct=Object.entries({reset:[0,0],bold:[1,22,"[22m[1m"],dim:[2,22,"[22m[2m"],italic:[3,23],underline:[4,24],inverse:[7,27],hidden:[8,28],strikethrough:[9,29],black:[30,39],red:[31,39],green:[32,39],yellow:[33,39],blue:[34,39],magenta:[35,39],cyan:[36,39],white:[37,39],gray:[90,39],bgBlack:[40,49],bgRed:[41,49],bgGreen:[42,49],bgYellow:[43,49],bgBlue:[44,49],bgMagenta:[45,49],bgCyan:[46,49],bgWhite:[47,49],blackBright:[90,39],redBright:[91,39],greenBright:[92,39],yellowBright:[93,39],blueBright:[94,39],magentaBright:[95,39],cyanBright:[96,39],whiteBright:[97,39],bgBlackBright:[100,49],bgRedBright:[101,49],bgGreenBright:[102,49],bgYellowBright:[103,49],bgBlueBright:[104,49],bgMagentaBright:[105,49],bgCyanBright:[106,49],bgWhiteBright:[107,49]});function dt(t){return String(t)}function lt(t=!1){let e=function(t=!1){let e="undefined"!=typeof process?process:void 0,r=(null==e?void 0:e.env)||{},n=(null==e?void 0:e.argv)||[];return!("NO_COLOR"in r||n.includes("--no-color"))&&("FORCE_COLOR"in r||n.includes("--color")||"win32"===(null==e?void 0:e.platform)||t&&"dumb"!==r.TERM||"CI"in r)||"undefined"!=typeof window&&!!window.chrome}(t),r=(t,e,r=t)=>{let n=n=>{let o=String(n),s=o.indexOf(e,t.length);return~s?t+((t,e,r,n)=>{let o="",s=0;do{o+=t.substring(s,n)+r,s=n+e.length,n=t.indexOf(e,s)}while(~n);return o+t.substring(s)})(o,e,r,s)+e:t+o+e};return n.open=t,n.close=e,n},n={isColorSupported:e},o=t=>`[${t}m`;for(let[t,s]of ct)n[t]=e?r(o(s[0]),o(s[1]),s[2]):dt;return n}dt.open="",dt.close="";const ut=t(import.meta.url)("tty");var ft=void 0!==process.env.FORCE_TTY||(0,ut.isatty)(1),ht=lt(ft);const pt={forceColor:!1,lineSeparator:"\r\n"};function gt(t,e=pt){e={...pt,...e};const{colorizeFn:r,resetColor:n}=function(t){const e=(t,e,r)=>(n,o)=>{switch(o){case"red":return t(n);case"green":return e(n);case"blue":return r(n);default:return n}};let r=()=>{};if("disable"===t.color)return{colorizeFn:t=>t,resetColor:r};if("force"===t.color){process.env.FORCE_COLOR||(process.env.FORCE_COLOR="1",r=()=>{delete process.env.FORCE_COLOR});const{red:t,green:n,blue:o}=lt(ft);return{colorizeFn:e(t,n,o),resetColor:r}}const{red:n,green:o,blue:s}=ht;return{colorizeFn:e(n,o,s),resetColor:r}}(e);try{const n=Array.isArray(t)?function(t,e){const r=[...mt(t,e),""];for(let n=0;n<t.length;n++){const o=t[n];r.push(bt(o),...wt(o,e)),n<t.length-1&&r.push("")}return r}(t,r):function(t,e){const r=[];if("number"==typeof t.faultInfo?.faultCode){let n=`${t.faultInfo.coreId}`;t.faultInfo.faultMessage&&(n+=` | ${t.faultInfo.faultMessage}`),n+=` | ${t.faultInfo.faultCode}`,r.push(e(n,"red"))}const n=t.faultInfo?.programCounter.location;n&&(r.length&&r.push(""),r.push(`${e("PC -> ","red")}${At(n,e)}`));const o=t.faultInfo?.faultAddr?.location;o&&r.push(`${e("Fault -> ","red")}${At(o,e)}`),t.stacktraceLines.length&&r.length&&r.push("");for(const n of t.stacktraceLines)r.push(At(n,e));return t.allocInfo&&(r.length&&r.push(""),r.push(`${e(`Memory allocation of ${t.allocInfo.allocSize} bytes failed`,"red")}${e(" at ")}${At(t.allocInfo.allocAddr,e)}`)),r}(t,r);return n.join(e.lineSeparator)}finally{n()}}function mt(t,e){const r=[];r.push("==================== THREADS INFO ===================="),r.push(" ID Target ID Frame");for(const n of t){const t=n.current?"*":" ",o=n.threadId.toString().padStart(2),s=n.TCB.toString().padEnd(12),i=n.result.stacktraceLines?.[0];r.push(` ${t}${o} process ${s} ${At(i,e)}`)}return r}function bt(t){return`==================== THREAD ${t.threadId} (TCB: 0x${(+t.TCB).toString(16)}) ====================`}function wt(t,e){return t.result.stacktraceLines.map((t=>At(t,e)))}function At(t,e){if("string"==typeof t)return e(t);if(!st(t))return`${e(t.regAddr,"green")}${e(`: ${t.lineNumber}`)}`;const r=t.args?.map((t=>`${t.name}${t.value?`=${t.value}`:""}`)).join(", ")??"",n=`${t.method} (${r})`;return`${e(t.regAddr,"green")}${e(": ")}${e(n,"blue")}${e(` at ${t.file}:${t.lineNumber}`)}`}var yt=r.lc,Ct=r.tI,It=r.jb,vt=r.D4,St=r.Br,Pt=r.bU,Et=r.xR,$t=r.M4,xt=r.aV,Bt=r.jp,Lt=r.Hx,Nt=r.mv,Ot=r.vl;export{yt as AbortError,Ct as arches,It as createDecodeParams,vt as decode,St as defaultTargetArch,Pt as findTargetArch,Et as findToolPath,$t as isDecodeTarget,xt as isGDBLine,Bt as isParsedGDBLine,Lt as isRiscvTargetArch,Nt as resolveToolPath,Ot as stringifyDecodeResult};
//# sourceMappingURL=lib.mjs.map