From c08a2707aff63727b377303f178c6b89e09c6fe8 Mon Sep 17 00:00:00 2001 From: "James G. Smith" Date: Wed, 13 May 2026 13:01:31 +0100 Subject: [PATCH 1/3] Add support for eCos/eCosPro --- README.md | 4 + images/eCos.png | Bin 0 -> 67428 bytes package.json | 3 +- src/rtos/rtos-ecos.ts | 440 ++++++++++++++++++++++++++++++++++++++++++ src/rtos/rtos.ts | 3 + 5 files changed, 449 insertions(+), 1 deletion(-) create mode 100644 images/eCos.png create mode 100644 src/rtos/rtos-ecos.ts diff --git a/README.md b/README.md index c27155c..2bb2610 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,9 @@ Here is an example of a uC/OS-III RTOS view Here is an example of an RTX5 RTOS view ![RTX5](./images/RTX5.png) +Here is an example of an eCos view +![eCos](./images/eCos.png) + NOTE: The tab name is in the screenshots is called `XRTOS` so it does not conflict with Cortex-Debug. Once the migration is complete, it will be called `RTOS` and Cortex-Debug itself will not have this functionality # Contributors and maintainers @@ -41,3 +44,4 @@ NOTE: The tab name is in the screenshots is called `XRTOS` so it does not confli | uC/OS-III | @github0null | | ThreadX | @raphaelmeyer | | RTX5 | @thorstendb-ARM | +| eCos | @RallySmith | diff --git a/images/eCos.png b/images/eCos.png new file mode 100644 index 0000000000000000000000000000000000000000..efec4004bce3fd4d079e153d623c1a72334f1b2f GIT binary patch literal 67428 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 stack expands from higher address to lower addresses + + private stale = true; + private timeInfo = ''; + private helpHtml: string | undefined; + + private foundThreads: RTOSCommon.RTOSThreadInfo[] = []; + private finalThreads: RTOSCommon.RTOSThreadInfo[] = []; + + // NOTE: under eCos the idle thread appears as a normal + // schedulable thread and so we do not need special handling; other + // than if we want to highlight it (e.g. special case handling of + // "cyg_idle_thread_loops[cpunum]" reporting) + constructor(public session: vscode.DebugSession) { + super(session, 'eCos'); + if (session.configuration.rtosViewConfig) { + if (session.configuration.rtosViewConfig.stackGrowth) { + this.stackIncrements = parseInt(session.configuration.rtosViewConfig.stackGrowth); + console.log('eCos: stackIncrements:', this.stackIncrements); + } + } + } + + public async tryDetect(useFrameId: number): Promise { + this.progStatus = 'stopped'; + try { + if (this.status === 'none') { //colType: numType + // Use "Cyg_Thread::thread_list" as basic eCos detection mechanism: + this.pxThreadList = await this.getVarIfEmpty(this.pxThreadList, useFrameId, 'Cyg_Thread::thread_list'); + // Vector holding per-CPU currently active thread pointer: "Cyg_Scheduler_Base::current_thread[CYGNUM_KERNEL_CPU_COUNT]" + this.xCurrentThread = await this.getVarIfEmpty(this.xCurrentThread, useFrameId, 'Cyg_Scheduler_Base::current_thread[0]'); + // ASCERTAIN: Best method to get information about the depth of the above vector (#CPUs in SMP configuration). + // Possibly use non-C symbol as per the thread stacked context shape symbols. + this.status = 'initialized'; + } + return this; + } catch (e) { + if (e instanceof RTOSCommon.ShouldRetry) { + console.error(e.message); + } else { + this.status = 'failed'; + this.failedWhy = e; + } + return this; + } + } + + protected createHmlHelp(th: RTOSCommon.RTOSThreadInfo, thInfo: RTOSCommon.RTOSStrToValueMap) { + function strong(text: string) { + return `${text}`; + } + if (this.helpHtml === undefined) { + this.helpHtml = ''; + try { + let ret: string = ''; + if (!thInfo['name']?.val) { + ret += 'Thread name missing: Enable ${strong("CYGVAR_KERNEL_THREADS_NAME")} if desired.
'; + } + // CONSIDER: Checking for further kernel features that may be useful for run-time diagnostics: + // e.g. CYGFUN_KERNEL_THREADS_STACK_LIMIT, CYGFUN_KERNEL_THREADS_STACK_MEASUREMENT, etc. + if (ret) { + ret += 'Note: Make sure to consider the performance/resources impact of any eCos configuration changes.
'; + this.helpHtml = '\n' + + '

\n${ret}\n

\n'; + } + } catch (e) { + console.log(e); + } + } + } + + private getThreadState(threadStatus: number, threadCurrent: boolean) { + let stateText = ''; + + if (threadStatus & ThreadStatus.SUSPENDED) { + stateText = 'suspended+'; + } + + switch (threadStatus & ~ThreadStatus.SUSPENDED) { + case ThreadStatus.RUNNING: + if (threadCurrent) { + stateText = 'running'; + } else if (threadStatus & ThreadStatus.SUSPENDED) { + stateText = 'suspended'; + } else { + stateText = 'ready'; + } + break; + case ThreadStatus.SLEEPING: + stateText = 'sleeping'; + break; + case ThreadStatus.SLEEPSET: + case ThreadStatus.COUNTSLEEP: + stateText = 'counted-sleep'; + break; + case ThreadStatus.CREATING: + stateText = 'creating'; + break; + case ThreadStatus.EXITED: + statedesc = 'exited'; + break; + default: + stateText = 'unknown'; + break; + } + + return stateText; + } + + protected async getStackInfo(thInfo: RTOSCommon.RTOSStrToValueMap | null, thHardware) { + const stackInfo: RTOSCommon.RTOSStackInfo = { + stackStart: 0, + }; + stackInfo.stackTop = 0; + + if (thInfo === null) { + return stackInfo; + } + + const stackBase = thHardware['stack_base'].val; + const stackLimit = thHardware['stack_limit'].val; + const stackSize = thHardware['stack_size'].val; + const stackPtr = thHardware['stack_ptr'].val; + + // If CYGFUN_KERNEL_THREADS_STACK_MEASUREMENT (with + // CYGNUM_KERNEL_THREADS_STACK_DATA_INIT as the init value) we could + // calculate the stackInfo.stackPeak value by checking the target + // memory. See rtos-embos.ts for an example implementation. + + if (stackSize && stackBase && stackLimit && stackPtr) { + const base = parseInt(stackBase); + const limit = parseInt(stackLimit); + const size = parseInt(stackSize); + const ptr = parseInt(stackPtr); + stackInfo.stackTop = Math.abs(base + size); + stackInfo.stackSize = size; + if (this.stackIncrements < 0) { + // Descending: + stackInfo.stackStart = limit; + stackInfo.stackEnd = stackInfo.stackTop; + stackInfo.stackFree = Math.abs(ptr - limit); + stackInfo.stackUsed = Math.abs(stackInfo.stackEnd - ptr); + } else { + // Ascending: + stackInfo.stackStart = stackInfo.stackTop; + stackInfo.stackEnd = limit; + stackInfo.stackFree = Math.abs(stackInfo.stackEnd- ptr); + stackInfo.stackUsed = Math.abs(ptr - stackInfo.stackStart); + } + } else { + // Force value since stackStart needs to be set: + stackInfo.stackStart = stackInfo.stackTop; + } + + return stackInfo; + } + + private getThreadInfo(thListHead: RTOSCommon.RTOSVarHelperMaybe, frameId: number): Promise { + return new Promise((resolve, reject) => { + if (!thListHead || !thListHead.varReference) { + resolve(); + return; + } + + if (this.progStatus !== 'stopped') { + reject(new Error('Busy')); + return; + } + + // thListHead is head object of circular linked list: + let thFirstAddress = parseInt(thListHead?.value || ''); + let thActiveAddress = undefined; + + // Only CPU[0] currently: + this.xCurrentThread?.getValue(frameId).then( + async(dummy: RTOSCommon.RTOSStrToValueMap) => { + try { + const thActive = await this.xCurrentThread; + thActiveAddress = parseInt(thActive?.value || ''); + } catch (e) { + console.log('RTOSeCos.getThreadInfo() xCurrentThread error', e); + } + }, + (e) => { + reject(e); + } + ); + + this.pxThreadList?.getVarChildrenObj(frameId).then( + async (thHead: RTOSCommon.RTOSStrToValueMap) => { + try { + let thCurrent = thHead; + let thAddress = thFirstAddress; + + do { + if (Object.hasOwn(thCurrent, 'list_next')) { + const thHardware = await this.getVarChildrenObj(thCurrent['Cyg_HardwareThread']?.ref, ''); + const thSched = await this.getVarChildrenObj(thCurrent['Cyg_SchedThread']?.ref, ''); + const thSchedImpl = await this.getVarChildrenObj(thSched['Cyg_SchedThread_Implementation']?.ref, ''); + + let thName = '[EMPTY]'; + if (thCurrent['name']) { + const matchName = thCurrent['name'].val.match(/"([^*]*)"$/); + thName = matchName ? matchName[1] : thName; + } + + let threadRunning = (thAddress === thActiveAddress); + const stackInfo = await this.getStackInfo(thCurrent, thHardware); + + const display: { [key: string]: RTOSCommon.DisplayRowItem } = {}; + const mySetter = (x: DisplayFields, text: string, value?: any) => { + display[DisplayFieldNames[x]] = { text, value }; + }; + + mySetter(DisplayFields.ID, thCurrent['unique_id'].val); + mySetter(DisplayFields.Address, RTOSCommon.hexFormat(thAddress)); + mySetter(DisplayFields.Priority, Math.abs(thSchedImpl['priority'].val)); // decimal + mySetter(DisplayFields.Status, this.getThreadState(thCurrent['state'].val, threadRunning)); + mySetter(DisplayFields.Name, thName); + if ((stackInfo.stackUsed !== undefined) && (stackInfo.stackSize !== undefined)) { + const stackPercentVal = Math.round((stackInfo.stackUsed / stackInfo.stackSize) * 100); + const stackPercentText = `${stackPercentVal} % (${stackInfo.stackUsed} / ${stackInfo.stackSize})`; + mySetter(DisplayFields.StackPercent, stackPercentText, stackPercentVal); + } else { + mySetter(DisplayFields.StackPercent, '[unknown]'); + } + mySetter(DisplayFields.StackBase, thHardware['stack_base'].val); // could use value de-referenced in getStackInfo() + mySetter(DisplayFields.StackLimit, RTOSCommon.hexFormat(stackInfo.stackStart)); + mySetter(DisplayFields.StackPtr, thHardware['stack_ptr'].val); + mySetter(DisplayFields.StackTop, RTOSCommon.hexFormat(stackInfo.stackTop)); + + const thread: RTOSCommon.RTOSThreadInfo = { + display: display, + stackInfo: stackInfo, + running: threadRunning, + }; + this.foundThreads.push(thread); + this.createHmlHelp(thread, thCurrent); + + thAddress = parseInt(thCurrent.list_next?.val); + if (0 !== thAddress) { + const thNextThread = await this.getVarChildrenObj(thCurrent.list_next?.ref, 'list_next'); + thCurrent = thNextThread || {}; + } + } else { + console.log('invalid eCos thread reference : no list_next'); + } + } while ((thAddress !== 0) && (thFirstAddress !== thAddress)); + + resolve(); + } catch (e) { + console.log('RTOSeCos.getThreadInfo() error', e); + } + }, + (e) => { + reject(e); + } + ); + }); + } + + public refresh(frameId: number): Promise { + return new Promise((resolve) => { + if (this.progStatus !== 'stopped') { + resolve(); + return; + } + + const timer = new RTOSCommon.HrTimer(); + + this.stale = true; + this.timeInfo = new Date().toISOString(); + this.foundThreads = []; + + this.pxThreadList?.getValue(frameId).then( + async (varObj: RTOSCommon.RTOSStrToValueMap) => { + try { + await this.getThreadInfo(this.pxThreadList, frameId); + this.foundThreads.sort((a, b) => parseInt(a.display['ID'].text) - parseInt(b.display['ID'].text)); + + this.finalThreads = [...this.foundThreads]; + this.stale = false; + this.timeInfo += ' in ' + timer.deltaMs() + 'ms'; + resolve(); + } catch (e) { + resolve(); + console.error('RTOSeCos.refresh() failed: ', e); + } + }, + (reason) => { + resolve(); + console.error('RTOSeCos.refresh() failed reason: ', reason); + } + ); + }); + } + + public lastValidHtmlContent: RTOSCommon.HtmlInfo = { html: '', css: '' }; + + public getHTML(): RTOSCommon.HtmlInfo { + const htmlContent: RTOSCommon.HtmlInfo = { html: '', css: '' }; + let msg = ''; + if (this.status === 'none') { + htmlContent.html = '

eCos not yet fully initialized. Will update the next time program pauses.

\n'; + return htmlContent; + } else if (this.stale) { + const lastHtmlInfo = this.lastValidHtmlContent; + msg = ' Following info from last query may be stale.'; + htmlContent.html = `

Unable to collect full eCos information.${msg}

\n` + lastHtmlInfo.html; + htmlContent.css = lastHtmlInfo.css; + return htmlContent; + } else if (this.finalThreads.length === 0) { + htmlContent.html = `

No ${this.name} threads detected, perhaps eCos is not yet initialized or threads are yet to be created!

\n`; + return htmlContent; + } + + const ret = this.getHTMLThreads(DisplayFieldNames, eCosItems, this.finalThreads, this.timeInfo); + // CONSIDER: Display other useful *global* eCos information (mutexes, memory pools, etc.) // see rtos-threadx.ts for example + htmlContent.html = msg + ret.html + (this.helpHtml || ''); + htmlContent.css = ret.css; + + this.lastValidHtmlContent = htmlContent; + return this.lastValidHtmlContent; + } +} diff --git a/src/rtos/rtos.ts b/src/rtos/rtos.ts index 6692de1..82ff80c 100644 --- a/src/rtos/rtos.ts +++ b/src/rtos/rtos.ts @@ -11,6 +11,7 @@ import { RTOSChibiOS } from './rtos-chibios'; import { RTOSZEPHYR } from './rtos-zephyr'; import { RTOSThreadX } from './rtos-threadx'; import { RTOSRTX5 } from './rtos-rtx5'; +import { RTOSeCos } from './rtos-ecos'; import { IDebugTracker, @@ -55,6 +56,8 @@ const RTOS_TYPES = { ThreadX: RTOSThreadX, // eslint-disable-next-line @typescript-eslint/naming-convention RTX5: RTOSRTX5, + // eslint-disable-next-line @typescript-eslint/naming-convention + eCos: RTOSeCos, }; const defaultHtmlInfo: RTOSCommon.HtmlInfo = { html: '', css: '' }; From 4eaae17a715997208223dc8f70d16147a6506e29 Mon Sep 17 00:00:00 2001 From: "James G. Smith" Date: Wed, 13 May 2026 14:46:28 +0100 Subject: [PATCH 2/3] Fix src/rtos/rtos-ecos.ts to allow `vsce package` --- src/rtos/rtos-ecos.ts | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/rtos/rtos-ecos.ts b/src/rtos/rtos-ecos.ts index 9c96534..c4273fb 100644 --- a/src/rtos/rtos-ecos.ts +++ b/src/rtos/rtos-ecos.ts @@ -51,7 +51,6 @@ eCosItems[DisplayFields[DisplayFields.Status]] = { width: 3, headerRow1: '', headerRow2: 'Status', - //colType: RTOSCommon.ColTypeEnum.colTypeCollapse }; eCosItems[DisplayFields[DisplayFields.Priority]] = { @@ -212,7 +211,7 @@ export class RTOSeCos extends RTOSCommon.RTOSBase { stateText = 'creating'; break; case ThreadStatus.EXITED: - statedesc = 'exited'; + stateText = 'exited'; break; default: stateText = 'unknown'; @@ -222,13 +221,13 @@ export class RTOSeCos extends RTOSCommon.RTOSBase { return stateText; } - protected async getStackInfo(thInfo: RTOSCommon.RTOSStrToValueMap | null, thHardware) { + protected async getStackInfo(thInfo: RTOSCommon.RTOSStrToValueMap | null, thHardware: RTOSCommon.RTOSStrToValueMap | null) { const stackInfo: RTOSCommon.RTOSStackInfo = { stackStart: 0, }; stackInfo.stackTop = 0; - if (thInfo === null) { + if ((thInfo === null) || (thHardware === null)) { return stackInfo; } @@ -284,11 +283,11 @@ export class RTOSeCos extends RTOSCommon.RTOSBase { // thListHead is head object of circular linked list: let thFirstAddress = parseInt(thListHead?.value || ''); - let thActiveAddress = undefined; + let thActiveAddress = 0; // Only CPU[0] currently: this.xCurrentThread?.getValue(frameId).then( - async(dummy: RTOSCommon.RTOSStrToValueMap) => { + async() => { try { const thActive = await this.xCurrentThread; thActiveAddress = parseInt(thActive?.value || ''); @@ -310,8 +309,8 @@ export class RTOSeCos extends RTOSCommon.RTOSBase { do { if (Object.hasOwn(thCurrent, 'list_next')) { const thHardware = await this.getVarChildrenObj(thCurrent['Cyg_HardwareThread']?.ref, ''); - const thSched = await this.getVarChildrenObj(thCurrent['Cyg_SchedThread']?.ref, ''); - const thSchedImpl = await this.getVarChildrenObj(thSched['Cyg_SchedThread_Implementation']?.ref, ''); + const thSched = await this.getVarChildrenObj(thCurrent['Cyg_SchedThread']?.ref, '') || {}; + const thSchedImpl = await this.getVarChildrenObj(thSched['Cyg_SchedThread_Implementation']?.ref, '') || {}; let thName = '[EMPTY]'; if (thCurrent['name']) { @@ -329,8 +328,8 @@ export class RTOSeCos extends RTOSCommon.RTOSBase { mySetter(DisplayFields.ID, thCurrent['unique_id'].val); mySetter(DisplayFields.Address, RTOSCommon.hexFormat(thAddress)); - mySetter(DisplayFields.Priority, Math.abs(thSchedImpl['priority'].val)); // decimal - mySetter(DisplayFields.Status, this.getThreadState(thCurrent['state'].val, threadRunning)); + mySetter(DisplayFields.Priority, Math.abs(parseInt(thSchedImpl['priority'].val)).toString()); // decimal + mySetter(DisplayFields.Status, this.getThreadState(parseInt(thCurrent['state'].val), threadRunning)); mySetter(DisplayFields.Name, thName); if ((stackInfo.stackUsed !== undefined) && (stackInfo.stackSize !== undefined)) { const stackPercentVal = Math.round((stackInfo.stackUsed / stackInfo.stackSize) * 100); @@ -339,10 +338,14 @@ export class RTOSeCos extends RTOSCommon.RTOSBase { } else { mySetter(DisplayFields.StackPercent, '[unknown]'); } - mySetter(DisplayFields.StackBase, thHardware['stack_base'].val); // could use value de-referenced in getStackInfo() - mySetter(DisplayFields.StackLimit, RTOSCommon.hexFormat(stackInfo.stackStart)); - mySetter(DisplayFields.StackPtr, thHardware['stack_ptr'].val); - mySetter(DisplayFields.StackTop, RTOSCommon.hexFormat(stackInfo.stackTop)); + if (thHardware) { + mySetter(DisplayFields.StackBase, thHardware['stack_base'].val); // could use value de-referenced in getStackInfo() + mySetter(DisplayFields.StackLimit, RTOSCommon.hexFormat(stackInfo.stackStart)); + mySetter(DisplayFields.StackPtr, thHardware['stack_ptr'].val); + if (stackInfo.stackTop !== undefined) { + mySetter(DisplayFields.StackTop, RTOSCommon.hexFormat(stackInfo.stackTop)); + } + } const thread: RTOSCommon.RTOSThreadInfo = { display: display, @@ -388,7 +391,7 @@ export class RTOSeCos extends RTOSCommon.RTOSBase { this.foundThreads = []; this.pxThreadList?.getValue(frameId).then( - async (varObj: RTOSCommon.RTOSStrToValueMap) => { + async (varObj) => { try { await this.getThreadInfo(this.pxThreadList, frameId); this.foundThreads.sort((a, b) => parseInt(a.display['ID'].text) - parseInt(b.display['ID'].text)); From bd9a93b41324bf04a791eea4ba7a8b3621e8319d Mon Sep 17 00:00:00 2001 From: "James G. Smith" Date: Sat, 16 May 2026 16:18:57 +0100 Subject: [PATCH 3/3] Fix eslint errors --- src/rtos/rtos-ecos.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/rtos/rtos-ecos.ts b/src/rtos/rtos-ecos.ts index c4273fb..70d8a90 100644 --- a/src/rtos/rtos-ecos.ts +++ b/src/rtos/rtos-ecos.ts @@ -168,7 +168,7 @@ export class RTOSeCos extends RTOSCommon.RTOSBase { try { let ret: string = ''; if (!thInfo['name']?.val) { - ret += 'Thread name missing: Enable ${strong("CYGVAR_KERNEL_THREADS_NAME")} if desired.
'; + ret += `Thread name missing: Enable ${strong('CYGVAR_KERNEL_THREADS_NAME')} if desired.
`; } // CONSIDER: Checking for further kernel features that may be useful for run-time diagnostics: // e.g. CYGFUN_KERNEL_THREADS_STACK_LIMIT, CYGFUN_KERNEL_THREADS_STACK_MEASUREMENT, etc. @@ -282,7 +282,7 @@ export class RTOSeCos extends RTOSCommon.RTOSBase { } // thListHead is head object of circular linked list: - let thFirstAddress = parseInt(thListHead?.value || ''); + const thFirstAddress = parseInt(thListHead?.value || ''); let thActiveAddress = 0; // Only CPU[0] currently: @@ -318,7 +318,7 @@ export class RTOSeCos extends RTOSCommon.RTOSBase { thName = matchName ? matchName[1] : thName; } - let threadRunning = (thAddress === thActiveAddress); + const threadRunning = (thAddress === thActiveAddress); const stackInfo = await this.getStackInfo(thCurrent, thHardware); const display: { [key: string]: RTOSCommon.DisplayRowItem } = {}; @@ -391,7 +391,7 @@ export class RTOSeCos extends RTOSCommon.RTOSBase { this.foundThreads = []; this.pxThreadList?.getValue(frameId).then( - async (varObj) => { + async () => { try { await this.getThreadInfo(this.pxThreadList, frameId); this.foundThreads.sort((a, b) => parseInt(a.display['ID'].text) - parseInt(b.display['ID'].text));