非機密扱い | ![]() | ARM DUI0446ZJ | ||
| ||||
ホーム > DS-5デバッガの OS 認識の記述 > スレッド認識の実装 |
スレッド認識は、おそらく実装で最も重要な部分です。
API での対応する呼び出しは、スレッドまたはタスクでの場合と同様に、getOSContextProvider()
です。ここで、context
は実行コンテキスト
を意味します。API では、Java インタフェースのインスタンス IOSContextProvider
が getOSContextProvider()
によって返されることが予期されます。このインタフェースは、前述の IOSProvider
と同じ JAR ファイル内のパッケージ com.arm.debug.extension.os.context
にあります。
myos タスクが次のような C タイプだと仮定します。
typedef enum { UNINITIALIZED = 0, READY } tstatus_t ; typedef struct{ uint32_t id; char *name; volatile tstatus_t status; uint32_t stack[STACK_SIZE]; uint32_t *sp; } task_t;
また、OS が常に現在実行中のタスクをタスク配列の最初の要素に保存すると仮定すると、さらに追加で行うコールバックが実装されて現在実行中の(またはスケジュール済みの)タスクおよびすべてのタスク(スケジュール済みのタスクとスケジュールされていないタスクの両方)を新しい contexts.py ファイルに返します。
<some folder> /mydb /OS /myos /extension.xml /messages.properties /provider.py /contexts.py
# this script implements the Java interface IOSProvider from osapi import DebugSessionException from contexts import ContextsProvider def areOSSymbolsLoaded(debugger): […] def isOSInitialised(debugger): […] def getOSContextProvider(): # returns an instance of the Java interface IOSContextProvider return ContextsProvider() def getDataModel(): […]
from osapi import ExecutionContext from osapi import ExecutionContextsProvider # this class implements the Java interface IOSContextProvider class ContextsProvider(ExecutionContextsProvider): def getCurrentOSContext(self, debugger): task = debugger.evaluateExpression("tasks[0]") return self.createContext(debugger, task) def getAllOSContexts(self, debugger): tasks = debugger.evaluateExpression("tasks").getArrayElements() contexts = [] for task in tasks: if task.getStructureMembers()["status"].readAsNumber() > 0: contexts.append(self.createContext(debugger, task)) return contexts def getOSContextSavedRegister(self, debugger, context, name): return None def createContext(self, debugger, task): members = task.getStructureMembers() id = members["id"].readAsNumber() name = members["name"].readAsNullTerminatedString() context = ExecutionContext(id, name, None) return context
getOSContextSavedRegister()
はまだ実装されていませんが、OS 認識が有効になるとすぐにデバッガで[Debug Control]ビューに OS タスクを入力するには、これで十分です。
タスクのレジスタ値がコアのレジスタから直接読み取られるため、現在実行中のタスクのコールスタックのデコードと、そのタスクの特定のスタックフレームのローカル変数の検査は、追加の変更なしに動作します。ただし、スケジュールされていないタスクの場合、切り替えるコンテキストで OS によって保存されたレジスタ値を読み取るために、getOSContextSavedRegister()
を実装する必要があります。これらの値を読み取る方法は、OS のコンテキスト切り替えロジックによってまったく異なります。
これが myos
の実装で、タスクが OS スケジューラによって切り替えられた場合にレジスタがスタックにプッシュされる M クラス ARM プロセッサの通常のコンテキスト切り替えルーチンに基づいています。
from osapi import ExecutionContext from osapi import ExecutionContextsProvider STACK_POINTER = "stack pointer" REGISTER_OFFSET_MAP = {"R4":0L, "R5":4L, "R6":8L, "R7":12L, "R8":16L, "R9":20L, "R10":24L, "R11":28L, "R0":32L, "R1":36L, "R2":40L, "R3":44L, "R12":48L, "LR":52L, "PC":56L, "XPSR":60L, "SP":64L} # this class implements the Java interface IOSContextProvider class ContextsProvider(ExecutionContextsProvider): def getCurrentOSContext(self, debugger): […] def getAllOSContexts(self, debugger): […] def getOSContextSavedRegister(self, debugger, context, name): offset = REGISTER_OFFSET_MAP.get(name) base = context.getAdditionalData()[STACK_POINTER] addr = base.addOffset(offset) if name == "SP": # SP itself isn’t pushed onto the stack:return its computed value return debugger.evaluateExpression("(long)" + str(addr)) else: # for any other register, return the value at the computed address return debugger.evaluateExpression("(long*)" + str(addr)) def createContext(self, debugger, task): members = task.getStructureMembers() id = members["id"].readAsNumber() name = members["name"].readAsNullTerminatedString() context = ExecutionContext(id, name, None) # record the stack address for this task in the context’s # additional data; this saves having to look it up later in # getOSContextSavedRegister() stackPointer = members["sp"].readAsAddress() context.getAdditionalData()[STACK_POINTER] = stackPointer return context
これで、デバッガは保存されたレジスタの値を取得できます。これにより、スケジュールされていないタスクのスタックを展開できます。