€•`¨Œsphinx.addnodes”Œdocument”“”)”}”(Œ rawsource”Œ”Œchildren”]”(Œ translations”Œ LanguagesNode”“”)”}”(hhh]”(hŒ pending_xref”“”)”}”(hhh]”Œdocutils.nodes”ŒText”“”ŒChinese (Simplified)”…””}”Œparent”hsbaŒ attributes”}”(Œids”]”Œclasses”]”Œnames”]”Œdupnames”]”Œbackrefs”]”Œ refdomain”Œstd”Œreftype”Œdoc”Œ reftarget”Œ1/translations/zh_CN/livepatch/reliable-stacktrace”Œmodname”NŒ classname”NŒ refexplicit”ˆuŒtagname”hhh ubh)”}”(hhh]”hŒChinese (Traditional)”…””}”hh2sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ1/translations/zh_TW/livepatch/reliable-stacktrace”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒItalian”…””}”hhFsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ1/translations/it_IT/livepatch/reliable-stacktrace”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒJapanese”…””}”hhZsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ1/translations/ja_JP/livepatch/reliable-stacktrace”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒKorean”…””}”hhnsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ1/translations/ko_KR/livepatch/reliable-stacktrace”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒSpanish”…””}”hh‚sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ1/translations/sp_SP/livepatch/reliable-stacktrace”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubeh}”(h]”h ]”h"]”h$]”h&]”Œcurrent_language”ŒEnglish”uh1h hhŒ _document”hŒsource”NŒline”NubhŒsection”“”)”}”(hhh]”(hŒtitle”“”)”}”(hŒReliable Stacktrace”h]”hŒReliable Stacktrace”…””}”(hh¨hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¦hh£hžhhŸŒK/var/lib/git/docbuild/linux/Documentation/livepatch/reliable-stacktrace.rst”h KubhŒ paragraph”“”)”}”(hŒEThis document outlines basic information about reliable stacktracing.”h]”hŒEThis document outlines basic information about reliable stacktracing.”…””}”(hh¹hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h Khh£hžhubhŒcomment”“”)”}”(hŒTable of Contents:”h]”hŒTable of Contents:”…””}”hhÉsbah}”(h]”h ]”h"]”h$]”h&]”Œ xml:space”Œpreserve”uh1hÇhh£hžhhŸh¶h KubhŒtopic”“”)”}”(hhh]”hŒ bullet_list”“”)”}”(hhh]”(hŒ list_item”“”)”}”(hhh]”h¸)”}”(hhh]”hŒ reference”“”)”}”(hhh]”hŒ1. Introduction”…””}”(hhíhžhhŸNh Nubah}”(h]”Œid1”ah ]”h"]”h$]”h&]”Œrefid”Œ introduction”uh1hëhhèubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hhåubah}”(h]”h ]”h"]”h$]”h&]”uh1hãhhàubhä)”}”(hhh]”h¸)”}”(hhh]”hì)”}”(hhh]”hŒ2. Requirements”…””}”(hjhžhhŸNh Nubah}”(h]”Œid2”ah ]”h"]”h$]”h&]”Œrefid”Œ requirements”uh1hëhj ubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hj ubah}”(h]”h ]”h"]”h$]”h&]”uh1hãhhàubhä)”}”(hhh]”h¸)”}”(hhh]”hì)”}”(hhh]”hŒ3. Compile-time analysis”…””}”(hj1hžhhŸNh Nubah}”(h]”Œid3”ah ]”h"]”h$]”h&]”Œrefid”Œcompile-time-analysis”uh1hëhj.ubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hj+ubah}”(h]”h ]”h"]”h$]”h&]”uh1hãhhàubhä)”}”(hhh]”(h¸)”}”(hhh]”hì)”}”(hhh]”hŒ4. Considerations”…””}”(hjShžhhŸNh Nubah}”(h]”Œid4”ah ]”h"]”h$]”h&]”Œrefid”Œconsiderations”uh1hëhjPubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hjMubhß)”}”(hhh]”(hä)”}”(hhh]”h¸)”}”(hhh]”hì)”}”(hhh]”hŒ&4.1 Identifying successful termination”…””}”(hjrhžhhŸNh Nubah}”(h]”Œid5”ah ]”h"]”h$]”h&]”Œrefid”Œ"identifying-successful-termination”uh1hëhjoubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hjlubah}”(h]”h ]”h"]”h$]”h&]”uh1hãhjiubhä)”}”(hhh]”h¸)”}”(hhh]”hì)”}”(hhh]”hŒ4.2 Identifying unwindable code”…””}”(hj”hžhhŸNh Nubah}”(h]”Œid6”ah ]”h"]”h$]”h&]”Œrefid”Œidentifying-unwindable-code”uh1hëhj‘ubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hjŽubah}”(h]”h ]”h"]”h$]”h&]”uh1hãhjiubhä)”}”(hhh]”h¸)”}”(hhh]”hì)”}”(hhh]”hŒ.4.3 Unwinding across interrupts and exceptions”…””}”(hj¶hžhhŸNh Nubah}”(h]”Œid7”ah ]”h"]”h$]”h&]”Œrefid”Œ*unwinding-across-interrupts-and-exceptions”uh1hëhj³ubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hj°ubah}”(h]”h ]”h"]”h$]”h&]”uh1hãhjiubhä)”}”(hhh]”h¸)”}”(hhh]”hì)”}”(hhh]”hŒ!4.4 Rewriting of return addresses”…””}”(hjØhžhhŸNh Nubah}”(h]”Œid8”ah ]”h"]”h$]”h&]”Œrefid”Œrewriting-of-return-addresses”uh1hëhjÕubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hjÒubah}”(h]”h ]”h"]”h$]”h&]”uh1hãhjiubhä)”}”(hhh]”h¸)”}”(hhh]”hì)”}”(hhh]”hŒ!4.5 Obscuring of return addresses”…””}”(hjúhžhhŸNh Nubah}”(h]”Œid9”ah ]”h"]”h$]”h&]”Œrefid”Œobscuring-of-return-addresses”uh1hëhj÷ubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hjôubah}”(h]”h ]”h"]”h$]”h&]”uh1hãhjiubhä)”}”(hhh]”h¸)”}”(hhh]”hì)”}”(hhh]”hŒ4.6 Link register unreliability”…””}”(hjhžhhŸNh Nubah}”(h]”Œid10”ah ]”h"]”h$]”h&]”Œrefid”Œlink-register-unreliability”uh1hëhjubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hjubah}”(h]”h ]”h"]”h$]”h&]”uh1hãhjiubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÞhjMubeh}”(h]”h ]”h"]”h$]”h&]”uh1hãhhàubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÞhhÛhžhhŸNh Nubah}”(h]”Œcontents”ah ]”(Œcontents”Œlocal”eh"]”Œcontents”ah$]”h&]”uh1hÙhŸh¶h K hh£hžhubh¢)”}”(hhh]”(h§)”}”(hŒ1. Introduction”h]”hŒ1. Introduction”…””}”(hjWhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”Œrefid”höuh1h¦hjThžhhŸh¶h K ubh¸)”}”(hŒØThe kernel livepatch consistency model relies on accurately identifying which functions may have live state and therefore may not be safe to patch. One way to identify which functions are live is to use a stacktrace.”h]”hŒØThe kernel livepatch consistency model relies on accurately identifying which functions may have live state and therefore may not be safe to patch. One way to identify which functions are live is to use a stacktrace.”…””}”(hjfhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h KhjThžhubh¸)”}”(hXEExisting stacktrace code may not always give an accurate picture of all functions with live state, and best-effort approaches which can be helpful for debugging are unsound for livepatching. Livepatching depends on architectures to provide a *reliable* stacktrace which ensures it never omits any live functions from a trace.”h]”(hŒòExisting stacktrace code may not always give an accurate picture of all functions with live state, and best-effort approaches which can be helpful for debugging are unsound for livepatching. Livepatching depends on architectures to provide a ”…””}”(hjthžhhŸNh NubhŒemphasis”“”)”}”(hŒ *reliable*”h]”hŒreliable”…””}”(hj~hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j|hjtubhŒI stacktrace which ensures it never omits any live functions from a trace.”…””}”(hjthžhhŸNh Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h KhjThžhubeh}”(h]”hüah ]”h"]”Œ1. introduction”ah$]”h&]”uh1h¡hh£hžhhŸh¶h K ubh¢)”}”(hhh]”(h§)”}”(hŒ2. Requirements”h]”hŒ2. Requirements”…””}”(hj hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”jejuh1h¦hjhžhhŸh¶h Kubh¸)”}”(hŒãArchitectures must implement one of the reliable stacktrace functions. Architectures using CONFIG_ARCH_STACKWALK must implement 'arch_stack_walk_reliable', and other architectures must implement 'save_stack_trace_tsk_reliable'.”h]”hŒëArchitectures must implement one of the reliable stacktrace functions. Architectures using CONFIG_ARCH_STACKWALK must implement ‘arch_stack_walk_reliable’, and other architectures must implement ‘save_stack_trace_tsk_reliable’.”…””}”(hj®hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h Khjhžhubh¸)”}”(hŒFPrincipally, the reliable stacktrace function must ensure that either:”h]”hŒFPrincipally, the reliable stacktrace function must ensure that either:”…””}”(hj¼hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h K!hjhžhubhß)”}”(hhh]”(hä)”}”(hŒ‡The trace includes all functions that the task may be returned to, and the return code is zero to indicate that the trace is reliable. ”h]”h¸)”}”(hŒ†The trace includes all functions that the task may be returned to, and the return code is zero to indicate that the trace is reliable.”h]”hŒ†The trace includes all functions that the task may be returned to, and the return code is zero to indicate that the trace is reliable.”…””}”(hjÑhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h K#hjÍubah}”(h]”h ]”h"]”h$]”h&]”uh1hãhjÊhžhhŸh¶h Nubhä)”}”(hŒHThe return code is non-zero to indicate that the trace is not reliable. ”h]”h¸)”}”(hŒGThe return code is non-zero to indicate that the trace is not reliable.”h]”hŒGThe return code is non-zero to indicate that the trace is not reliable.”…””}”(hjéhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h K&hjåubah}”(h]”h ]”h"]”h$]”h&]”uh1hãhjÊhžhhŸh¶h Nubeh}”(h]”h ]”h"]”h$]”h&]”Œbullet”Œ*”uh1hÞhŸh¶h K#hjhžhubhŒnote”“”)”}”(hŒ¦In some cases it is legitimate to omit specific functions from the trace, but all other functions must be reported. These cases are described in further detail below.”h]”h¸)”}”(hŒ¦In some cases it is legitimate to omit specific functions from the trace, but all other functions must be reported. These cases are described in further detail below.”h]”hŒ¦In some cases it is legitimate to omit specific functions from the trace, but all other functions must be reported. These cases are described in further detail below.”…””}”(hj hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h K)hjubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjhžhhŸh¶h Nubh¸)”}”(hXfSecondly, the reliable stacktrace function must be robust to cases where the stack or other unwind state is corrupt or otherwise unreliable. The function should attempt to detect such cases and return a non-zero error code, and should not get stuck in an infinite loop or access memory in an unsafe way. Specific cases are described in further detail below.”h]”hXfSecondly, the reliable stacktrace function must be robust to cases where the stack or other unwind state is corrupt or otherwise unreliable. The function should attempt to detect such cases and return a non-zero error code, and should not get stuck in an infinite loop or access memory in an unsafe way. Specific cases are described in further detail below.”…””}”(hjhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h K-hjhžhubeh}”(h]”jah ]”h"]”Œ2. requirements”ah$]”h&]”uh1h¡hh£hžhhŸh¶h Kubh¢)”}”(hhh]”(h§)”}”(hŒ3. Compile-time analysis”h]”hŒ3. Compile-time analysis”…””}”(hj7hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”jej:uh1h¦hj4hžhhŸh¶h K5ubh¸)”}”(hX£To ensure that kernel code can be correctly unwound in all cases, architectures may need to verify that code has been compiled in a manner expected by the unwinder. For example, an unwinder may expect that functions manipulate the stack pointer in a limited way, or that all functions use specific prologue and epilogue sequences. Architectures with such requirements should verify the kernel compilation using objtool.”h]”hX£To ensure that kernel code can be correctly unwound in all cases, architectures may need to verify that code has been compiled in a manner expected by the unwinder. For example, an unwinder may expect that functions manipulate the stack pointer in a limited way, or that all functions use specific prologue and epilogue sequences. Architectures with such requirements should verify the kernel compilation using objtool.”…””}”(hjEhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h K7hj4hžhubh¸)”}”(hŒ”In some cases, an unwinder may require metadata to correctly unwind. Where necessary, this metadata should be generated at build time using objtool.”h]”hŒ”In some cases, an unwinder may require metadata to correctly unwind. Where necessary, this metadata should be generated at build time using objtool.”…””}”(hjShžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h K?hj4hžhubeh}”(h]”j@ah ]”h"]”Œ3. compile-time analysis”ah$]”h&]”uh1h¡hh£hžhhŸh¶h K5ubh¢)”}”(hhh]”(h§)”}”(hŒ4. Considerations”h]”hŒ4. Considerations”…””}”(hjkhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”jej\uh1h¦hjhhžhhŸh¶h KEubh¸)”}”(hŒÂThe unwinding process varies across architectures, their respective procedure call standards, and kernel configurations. This section describes common details that architectures should consider.”h]”hŒÂThe unwinding process varies across architectures, their respective procedure call standards, and kernel configurations. This section describes common details that architectures should consider.”…””}”(hjyhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h KGhjhhžhubh¢)”}”(hhh]”(h§)”}”(hŒ&4.1 Identifying successful termination”h]”hŒ&4.1 Identifying successful termination”…””}”(hjŠhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”jej{uh1h¦hj‡hžhhŸh¶h KLubh¸)”}”(hŒAUnwinding may terminate early for a number of reasons, including:”h]”hŒAUnwinding may terminate early for a number of reasons, including:”…””}”(hj˜hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h KNhj‡hžhubhß)”}”(hhh]”(hä)”}”(hŒ#Stack or frame pointer corruption. ”h]”h¸)”}”(hŒ"Stack or frame pointer corruption.”h]”hŒ"Stack or frame pointer corruption.”…””}”(hj­hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h KPhj©ubah}”(h]”h ]”h"]”h$]”h&]”uh1hãhj¦hžhhŸh¶h Nubhä)”}”(hŒKMissing unwind support for an uncommon scenario, or a bug in the unwinder. ”h]”h¸)”}”(hŒJMissing unwind support for an uncommon scenario, or a bug in the unwinder.”h]”hŒJMissing unwind support for an uncommon scenario, or a bug in the unwinder.”…””}”(hjÅhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h KRhjÁubah}”(h]”h ]”h"]”h$]”h&]”uh1hãhj¦hžhhŸh¶h Nubhä)”}”(hŒ‹Dynamically generated code (e.g. eBPF) or foreign code (e.g. EFI runtime services) not following the conventions expected by the unwinder. ”h]”h¸)”}”(hŒŠDynamically generated code (e.g. eBPF) or foreign code (e.g. EFI runtime services) not following the conventions expected by the unwinder.”h]”hŒŠDynamically generated code (e.g. eBPF) or foreign code (e.g. EFI runtime services) not following the conventions expected by the unwinder.”…””}”(hjÝhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h KThjÙubah}”(h]”h ]”h"]”h$]”h&]”uh1hãhj¦hžhhŸh¶h Nubeh}”(h]”h ]”h"]”h$]”h&]”jjuh1hÞhŸh¶h KPhj‡hžhubh¸)”}”(hŒÜTo ensure that this does not result in functions being omitted from the trace, even if not caught by other checks, it is strongly recommended that architectures verify that a stacktrace ends at an expected location, e.g.”h]”hŒÜTo ensure that this does not result in functions being omitted from the trace, even if not caught by other checks, it is strongly recommended that architectures verify that a stacktrace ends at an expected location, e.g.”…””}”(hj÷hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h KWhj‡hžhubhß)”}”(hhh]”(hä)”}”(hŒAWithin a specific function that is an entry point to the kernel. ”h]”h¸)”}”(hŒ@Within a specific function that is an entry point to the kernel.”h]”hŒ@Within a specific function that is an entry point to the kernel.”…””}”(hj hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h K[hjubah}”(h]”h ]”h"]”h$]”h&]”uh1hãhjhžhhŸh¶h Nubhä)”}”(hŒEAt a specific location on a stack expected for a kernel entry point. ”h]”h¸)”}”(hŒDAt a specific location on a stack expected for a kernel entry point.”h]”hŒDAt a specific location on a stack expected for a kernel entry point.”…””}”(hj$hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h K]hj ubah}”(h]”h ]”h"]”h$]”h&]”uh1hãhjhžhhŸh¶h Nubhä)”}”(hŒsOn a specific stack expected for a kernel entry point (e.g. if the architecture has separate task and IRQ stacks). ”h]”h¸)”}”(hŒrOn a specific stack expected for a kernel entry point (e.g. if the architecture has separate task and IRQ stacks).”h]”hŒrOn a specific stack expected for a kernel entry point (e.g. if the architecture has separate task and IRQ stacks).”…””}”(hj<hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h K_hj8ubah}”(h]”h ]”h"]”h$]”h&]”uh1hãhjhžhhŸh¶h Nubeh}”(h]”h ]”h"]”h$]”h&]”jjuh1hÞhŸh¶h K[hj‡hžhubeh}”(h]”jah ]”h"]”Œ&4.1 identifying successful termination”ah$]”h&]”uh1h¡hjhhžhhŸh¶h KLubh¢)”}”(hhh]”(h§)”}”(hŒ4.2 Identifying unwindable code”h]”hŒ4.2 Identifying unwindable code”…””}”(hj`hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”jejuh1h¦hj]hžhhŸh¶h Kcubh¸)”}”(hŒÚUnwinding typically relies on code following specific conventions (e.g. manipulating a frame pointer), but there can be code which may not follow these conventions and may require special handling in the unwinder, e.g.”h]”hŒÚUnwinding typically relies on code following specific conventions (e.g. manipulating a frame pointer), but there can be code which may not follow these conventions and may require special handling in the unwinder, e.g.”…””}”(hjnhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h Kehj]hžhubhß)”}”(hhh]”(hä)”}”(hŒ&Exception vectors and entry assembly. ”h]”h¸)”}”(hŒ%Exception vectors and entry assembly.”h]”hŒ%Exception vectors and entry assembly.”…””}”(hjƒhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h Kihjubah}”(h]”h ]”h"]”h$]”h&]”uh1hãhj|hžhhŸh¶h Nubhä)”}”(hŒDynamically generated code (e.g. eBPF, optprobe trampolines). ”h]”h¸)”}”(hŒ=Dynamically generated code (e.g. eBPF, optprobe trampolines).”h]”hŒ=Dynamically generated code (e.g. eBPF, optprobe trampolines).”…””}”(hjËhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h KohjÇubah}”(h]”h ]”h"]”h$]”h&]”uh1hãhj|hžhhŸh¶h Nubhä)”}”(hŒ*Foreign code (e.g. EFI runtime services). ”h]”h¸)”}”(hŒ)Foreign code (e.g. EFI runtime services).”h]”hŒ)Foreign code (e.g. EFI runtime services).”…””}”(hjãhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h Kqhjßubah}”(h]”h ]”h"]”h$]”h&]”uh1hãhj|hžhhŸh¶h Nubeh}”(h]”h ]”h"]”h$]”h&]”jjuh1hÞhŸh¶h Kihj]hžhubh¸)”}”(hŒïTo ensure that such cases do not result in functions being omitted from a trace, it is strongly recommended that architectures positively identify code which is known to be reliable to unwind from, and reject unwinding from all other code.”h]”hŒïTo ensure that such cases do not result in functions being omitted from a trace, it is strongly recommended that architectures positively identify code which is known to be reliable to unwind from, and reject unwinding from all other code.”…””}”(hjýhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h Kshj]hžhubh¸)”}”(hŒ§Kernel code including modules and eBPF can be distinguished from foreign code using '__kernel_text_address()'. Checking for this also helps to detect stack corruption.”h]”hŒ«Kernel code including modules and eBPF can be distinguished from foreign code using ‘__kernel_text_address()’. Checking for this also helps to detect stack corruption.”…””}”(hj hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h Kxhj]hžhubh¸)”}”(hŒoThere are several ways an architecture may identify kernel code which is deemed unreliable to unwind from, e.g.”h]”hŒoThere are several ways an architecture may identify kernel code which is deemed unreliable to unwind from, e.g.”…””}”(hjhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h K|hj]hžhubhß)”}”(hhh]”(hä)”}”(hŒiPlacing such code into special linker sections, and rejecting unwinding from any code in these sections. ”h]”h¸)”}”(hŒhPlacing such code into special linker sections, and rejecting unwinding from any code in these sections.”h]”hŒhPlacing such code into special linker sections, and rejecting unwinding from any code in these sections.”…””}”(hj.hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h Khj*ubah}”(h]”h ]”h"]”h$]”h&]”uh1hãhj'hžhhŸh¶h Nubhä)”}”(hŒ@Identifying specific portions of code using bounds information. ”h]”h¸)”}”(hŒ?Identifying specific portions of code using bounds information.”h]”hŒ?Identifying specific portions of code using bounds information.”…””}”(hjFhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h K‚hjBubah}”(h]”h ]”h"]”h$]”h&]”uh1hãhj'hžhhŸh¶h Nubeh}”(h]”h ]”h"]”h$]”h&]”jjuh1hÞhŸh¶h Khj]hžhubeh}”(h]”j£ah ]”h"]”Œ4.2 identifying unwindable code”ah$]”h&]”uh1h¡hjhhžhhŸh¶h Kcubh¢)”}”(hhh]”(h§)”}”(hŒ.4.3 Unwinding across interrupts and exceptions”h]”hŒ.4.3 Unwinding across interrupts and exceptions”…””}”(hjjhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”jej¿uh1h¦hjghžhhŸh¶h K…ubh¸)”}”(hXÞAt function call boundaries the stack and other unwind state is expected to be in a consistent state suitable for reliable unwinding, but this may not be the case part-way through a function. For example, during a function prologue or epilogue a frame pointer may be transiently invalid, or during the function body the return address may be held in an arbitrary general purpose register. For some architectures this may change at runtime as a result of dynamic instrumentation.”h]”hXÞAt function call boundaries the stack and other unwind state is expected to be in a consistent state suitable for reliable unwinding, but this may not be the case part-way through a function. For example, during a function prologue or epilogue a frame pointer may be transiently invalid, or during the function body the return address may be held in an arbitrary general purpose register. For some architectures this may change at runtime as a result of dynamic instrumentation.”…””}”(hjxhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h K‡hjghžhubh¸)”}”(hXIf an interrupt or other exception is taken while the stack or other unwind state is in an inconsistent state, it may not be possible to reliably unwind, and it may not be possible to identify whether such unwinding will be reliable. See below for examples.”h]”hXIf an interrupt or other exception is taken while the stack or other unwind state is in an inconsistent state, it may not be possible to reliably unwind, and it may not be possible to identify whether such unwinding will be reliable. See below for examples.”…””}”(hj†hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h Khjghžhubh¸)”}”(hX(Architectures which cannot identify when it is reliable to unwind such cases (or where it is never reliable) must reject unwinding across exception boundaries. Note that it may be reliable to unwind across certain exceptions (e.g. IRQ) but unreliable to unwind across other exceptions (e.g. NMI).”h]”hX(Architectures which cannot identify when it is reliable to unwind such cases (or where it is never reliable) must reject unwinding across exception boundaries. Note that it may be reliable to unwind across certain exceptions (e.g. IRQ) but unreliable to unwind across other exceptions (e.g. NMI).”…””}”(hj”hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h K”hjghžhubh¸)”}”(hXArchitectures which can identify when it is reliable to unwind such cases (or have no such cases) should attempt to unwind across exception boundaries, as doing so can prevent unnecessarily stalling livepatch consistency checks and permits livepatch transitions to complete more quickly.”h]”hXArchitectures which can identify when it is reliable to unwind such cases (or have no such cases) should attempt to unwind across exception boundaries, as doing so can prevent unnecessarily stalling livepatch consistency checks and permits livepatch transitions to complete more quickly.”…””}”(hj¢hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h Kšhjghžhubeh}”(h]”jÅah ]”h"]”Œ.4.3 unwinding across interrupts and exceptions”ah$]”h&]”uh1h¡hjhhžhhŸh¶h K…ubh¢)”}”(hhh]”(h§)”}”(hŒ!4.4 Rewriting of return addresses”h]”hŒ!4.4 Rewriting of return addresses”…””}”(hjºhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”jejáuh1h¦hj·hžhhŸh¶h K ubh¸)”}”(hŒ”Some trampolines temporarily modify the return address of a function in order to intercept when that function returns with a return trampoline, e.g.”h]”hŒ”Some trampolines temporarily modify the return address of a function in order to intercept when that function returns with a return trampoline, e.g.”…””}”(hjÈhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h K¢hj·hžhubhß)”}”(hhh]”(hä)”}”(hŒiAn ftrace trampoline may modify the return address so that function graph tracing can intercept returns. ”h]”h¸)”}”(hŒhAn ftrace trampoline may modify the return address so that function graph tracing can intercept returns.”h]”hŒhAn ftrace trampoline may modify the return address so that function graph tracing can intercept returns.”…””}”(hjÝhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h K¥hjÙubah}”(h]”h ]”h"]”h$]”h&]”uh1hãhjÖhžhhŸh¶h Nubhä)”}”(hŒlA kprobes (or optprobes) trampoline may modify the return address so that kretprobes can intercept returns. ”h]”h¸)”}”(hŒkA kprobes (or optprobes) trampoline may modify the return address so that kretprobes can intercept returns.”h]”hŒkA kprobes (or optprobes) trampoline may modify the return address so that kretprobes can intercept returns.”…””}”(hjõhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h K¨hjñubah}”(h]”h ]”h"]”h$]”h&]”uh1hãhjÖhžhhŸh¶h Nubeh}”(h]”h ]”h"]”h$]”h&]”jjuh1hÞhŸh¶h K¥hj·hžhubh¸)”}”(hXªWhen this happens, the original return address will not be in its usual location. For trampolines which are not subject to live patching, where an unwinder can reliably determine the original return address and no unwind state is altered by the trampoline, the unwinder may report the original return address in place of the trampoline and report this as reliable. Otherwise, an unwinder must report these cases as unreliable.”h]”hXªWhen this happens, the original return address will not be in its usual location. For trampolines which are not subject to live patching, where an unwinder can reliably determine the original return address and no unwind state is altered by the trampoline, the unwinder may report the original return address in place of the trampoline and report this as reliable. Otherwise, an unwinder must report these cases as unreliable.”…””}”(hjhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h K«hj·hžhubh¸)”}”(hXSpecial care is required when identifying the original return address, as this information is not in a consistent location for the duration of the entry trampoline or return trampoline. For example, considering the x86_64 'return_to_handler' return trampoline:”h]”hXSpecial care is required when identifying the original return address, as this information is not in a consistent location for the duration of the entry trampoline or return trampoline. For example, considering the x86_64 ‘return_to_handler’ return trampoline:”…””}”(hjhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h K²hj·hžhubhŒ literal_block”“”)”}”(hXSYM_CODE_START(return_to_handler) UNWIND_HINT_UNDEFINED subq $24, %rsp /* Save the return values */ movq %rax, (%rsp) movq %rdx, 8(%rsp) movq %rbp, %rdi call ftrace_return_to_handler movq %rax, %rdi movq 8(%rsp), %rdx movq (%rsp), %rax addq $24, %rsp JMP_NOSPEC rdi SYM_CODE_END(return_to_handler)”h]”hXSYM_CODE_START(return_to_handler) UNWIND_HINT_UNDEFINED subq $24, %rsp /* Save the return values */ movq %rax, (%rsp) movq %rdx, 8(%rsp) movq %rbp, %rdi call ftrace_return_to_handler movq %rax, %rdi movq 8(%rsp), %rdx movq (%rsp), %rax addq $24, %rsp JMP_NOSPEC rdi SYM_CODE_END(return_to_handler)”…””}”hj-sbah}”(h]”h ]”h"]”h$]”h&]”h×hØŒforce”‰Œlanguage”Œnone”Œhighlight_args”}”uh1j+hŸh¶h K·hj·hžhubh¸)”}”(hXWhile the traced function runs its return address on the stack points to the start of return_to_handler, and the original return address is stored in the task's cur_ret_stack. During this time the unwinder can find the return address using ftrace_graph_ret_addr().”h]”hX While the traced function runs its return address on the stack points to the start of return_to_handler, and the original return address is stored in the task’s cur_ret_stack. During this time the unwinder can find the return address using ftrace_graph_ret_addr().”…””}”(hj@hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h KËhj·hžhubh¸)”}”(hX³When the traced function returns to return_to_handler, there is no longer a return address on the stack, though the original return address is still stored in the task's cur_ret_stack. Within ftrace_return_to_handler(), the original return address is removed from cur_ret_stack and is transiently moved arbitrarily by the compiler before being returned in rax. The return_to_handler trampoline moves this into rdi before jumping to it.”h]”hXµWhen the traced function returns to return_to_handler, there is no longer a return address on the stack, though the original return address is still stored in the task’s cur_ret_stack. Within ftrace_return_to_handler(), the original return address is removed from cur_ret_stack and is transiently moved arbitrarily by the compiler before being returned in rax. The return_to_handler trampoline moves this into rdi before jumping to it.”…””}”(hjNhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h KÐhj·hžhubh¸)”}”(hŒÚArchitectures might not always be able to unwind such sequences, such as when ftrace_return_to_handler() has removed the address from cur_ret_stack, and the location of the return address cannot be reliably determined.”h]”hŒÚArchitectures might not always be able to unwind such sequences, such as when ftrace_return_to_handler() has removed the address from cur_ret_stack, and the location of the return address cannot be reliably determined.”…””}”(hj\hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h K×hj·hžhubh¸)”}”(hX=It is recommended that architectures unwind cases where return_to_handler has not yet been returned to, but architectures are not required to unwind from the middle of return_to_handler and can report this as unreliable. Architectures are not required to unwind from other trampolines which modify the return address.”h]”hX=It is recommended that architectures unwind cases where return_to_handler has not yet been returned to, but architectures are not required to unwind from the middle of return_to_handler and can report this as unreliable. Architectures are not required to unwind from other trampolines which modify the return address.”…””}”(hjjhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h KÛhj·hžhubeh}”(h]”jçah ]”h"]”Œ!4.4 rewriting of return addresses”ah$]”h&]”uh1h¡hjhhžhhŸh¶h K ubh¢)”}”(hhh]”(h§)”}”(hŒ!4.5 Obscuring of return addresses”h]”hŒ!4.5 Obscuring of return addresses”…””}”(hj‚hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”jejuh1h¦hjhžhhŸh¶h Kâubh¸)”}”(hŒ–Some trampolines do not rewrite the return address in order to intercept returns, but do transiently clobber the return address or other unwind state.”h]”hŒ–Some trampolines do not rewrite the return address in order to intercept returns, but do transiently clobber the return address or other unwind state.”…””}”(hjhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h Kähjhžhubh¸)”}”(hX3For example, the x86_64 implementation of optprobes patches the probed function with a JMP instruction which targets the associated optprobe trampoline. When the probe is hit, the CPU will branch to the optprobe trampoline, and the address of the probed function is not held in any register or on the stack.”h]”hX3For example, the x86_64 implementation of optprobes patches the probed function with a JMP instruction which targets the associated optprobe trampoline. When the probe is hit, the CPU will branch to the optprobe trampoline, and the address of the probed function is not held in any register or on the stack.”…””}”(hjžhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h Kçhjhžhubh¸)”}”(hŒlSimilarly, the arm64 implementation of DYNAMIC_FTRACE_WITH_REGS patches traced functions with the following:”h]”hŒlSimilarly, the arm64 implementation of DYNAMIC_FTRACE_WITH_REGS patches traced functions with the following:”…””}”(hj¬hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h Kìhjhžhubj,)”}”(hŒMOV X9, X30 BL ”h]”hŒMOV X9, X30 BL ”…””}”hjºsbah}”(h]”h ]”h"]”h$]”h&]”h×hØj;‰j<Œnone”j>}”uh1j+hŸh¶h Kïhjhžhubh¸)”}”(hXThe MOV saves the link register (X30) into X9 to preserve the return address before the BL clobbers the link register and branches to the trampoline. At the start of the trampoline, the address of the traced function is in X9 rather than the link register as would usually be the case.”h]”hXThe MOV saves the link register (X30) into X9 to preserve the return address before the BL clobbers the link register and branches to the trampoline. At the start of the trampoline, the address of the traced function is in X9 rather than the link register as would usually be the case.”…””}”(hjÊhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h Kôhjhžhubh¸)”}”(hŒyArchitectures must either ensure that unwinders either reliably unwind such cases, or report the unwinding as unreliable.”h]”hŒyArchitectures must either ensure that unwinders either reliably unwind such cases, or report the unwinding as unreliable.”…””}”(hjØhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h Kùhjhžhubeh}”(h]”j ah ]”h"]”Œ!4.5 obscuring of return addresses”ah$]”h&]”uh1h¡hjhhžhhŸh¶h Kâubh¢)”}”(hhh]”(h§)”}”(hŒ4.6 Link register unreliability”h]”hŒ4.6 Link register unreliability”…””}”(hjðhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”jej%uh1h¦hjíhžhhŸh¶h Kýubh¸)”}”(hXÁOn some other architectures, 'call' instructions place the return address into a link register, and 'return' instructions consume the return address from the link register without modifying the register. On these architectures software must save the return address to the stack prior to making a function call. Over the duration of a function call, the return address may be held in the link register alone, on the stack alone, or in both locations.”h]”hXÉOn some other architectures, ‘call’ instructions place the return address into a link register, and ‘return’ instructions consume the return address from the link register without modifying the register. On these architectures software must save the return address to the stack prior to making a function call. Over the duration of a function call, the return address may be held in the link register alone, on the stack alone, or in both locations.”…””}”(hjþhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h Kÿhjíhžhubh¸)”}”(hŒ¿Unwinders typically assume the link register is always live, but this assumption can lead to unreliable stack traces. For example, consider the following arm64 assembly for a simple function:”h]”hŒ¿Unwinders typically assume the link register is always live, but this assumption can lead to unreliable stack traces. For example, consider the following arm64 assembly for a simple function:”…””}”(hj hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h Mhjíhžhubj,)”}”(hŒ†function: STP X29, X30, [SP, -16]! MOV X29, SP BL LDP X29, X30, [SP], #16 RET”h]”hŒ†function: STP X29, X30, [SP, -16]! MOV X29, SP BL LDP X29, X30, [SP], #16 RET”…””}”hjsbah}”(h]”h ]”h"]”h$]”h&]”h×hØj;‰j<Œnone”j>}”uh1j+hŸh¶h M hjíhžhubh¸)”}”(hXAt entry to the function, the link register (x30) points to the caller, and the frame pointer (X29) points to the caller's frame including the caller's return address. The first two instructions create a new stackframe and update the frame pointer, and at this point the link register and the frame pointer both describe this function's return address. A trace at this point may describe this function twice, and if the function return is being traced, the unwinder may consume two entries from the fgraph return stack rather than one entry.”h]”hX#At entry to the function, the link register (x30) points to the caller, and the frame pointer (X29) points to the caller’s frame including the caller’s return address. The first two instructions create a new stackframe and update the frame pointer, and at this point the link register and the frame pointer both describe this function’s return address. A trace at this point may describe this function twice, and if the function return is being traced, the unwinder may consume two entries from the fgraph return stack rather than one entry.”…””}”(hj*hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h Mhjíhžhubh¸)”}”(hX;The BL invokes 'other_function' with the link register pointing to this function's LDR and the frame pointer pointing to this function's stackframe. When 'other_function' returns, the link register is left pointing at the BL, and so a trace at this point could result in 'function' appearing twice in the backtrace.”h]”hXKThe BL invokes ‘other_function’ with the link register pointing to this function’s LDR and the frame pointer pointing to this function’s stackframe. When ‘other_function’ returns, the link register is left pointing at the BL, and so a trace at this point could result in ‘function’ appearing twice in the backtrace.”…””}”(hj8hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h Mhjíhžhubh¸)”}”(hŒ;Similarly, a function may deliberately clobber the LR, e.g.”h]”hŒ;Similarly, a function may deliberately clobber the LR, e.g.”…””}”(hjFhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h M!hjíhžhubj,)”}”(hŒcaller: STP X29, X30, [SP, -16]! MOV X29, SP ADR LR, BLR LR LDP X29, X30, [SP], #16 RET”h]”hŒcaller: STP X29, X30, [SP, -16]! MOV X29, SP ADR LR, BLR LR LDP X29, X30, [SP], #16 RET”…””}”hjTsbah}”(h]”h ]”h"]”h$]”h&]”h×hØj;‰j<Œnone”j>}”uh1j+hŸh¶h M#hjíhžhubh¸)”}”(hŒÔThe ADR places the address of 'callee' into the LR, before the BLR branches to this address. If a trace is made immediately after the ADR, 'callee' will appear to be the parent of 'caller', rather than the child.”h]”hŒàThe ADR places the address of ‘callee’ into the LR, before the BLR branches to this address. If a trace is made immediately after the ADR, ‘callee’ will appear to be the parent of ‘caller’, rather than the child.”…””}”(hjdhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h M-hjíhžhubh¸)”}”(hXMDue to cases such as the above, it may only be possible to reliably consume a link register value at a function call boundary. Architectures where this is the case must reject unwinding across exception boundaries unless they can reliably identify when the LR or stack value should be used (e.g. using metadata generated by objtool).”h]”hXMDue to cases such as the above, it may only be possible to reliably consume a link register value at a function call boundary. Architectures where this is the case must reject unwinding across exception boundaries unless they can reliably identify when the LR or stack value should be used (e.g. using metadata generated by objtool).”…””}”(hjrhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h M1hjíhžhubeh}”(h]”j+ah ]”h"]”Œ4.6 link register unreliability”ah$]”h&]”uh1h¡hjhhžhhŸh¶h Kýubeh}”(h]”jbah ]”h"]”Œ4. considerations”ah$]”h&]”uh1h¡hh£hžhhŸh¶h KEubeh}”(h]”Œreliable-stacktrace”ah ]”h"]”Œreliable stacktrace”ah$]”h&]”uh1h¡hhhžhhŸh¶h Kubeh}”(h]”h ]”h"]”h$]”h&]”Œsource”h¶uh1hŒcurrent_source”NŒ current_line”NŒsettings”Œdocutils.frontend”ŒValues”“”)”}”(h¦NŒ generator”NŒ datestamp”NŒ source_link”NŒ source_url”NŒ toc_backlinks”Œentry”Œfootnote_backlinks”KŒ sectnum_xform”KŒstrip_comments”NŒstrip_elements_with_classes”NŒ strip_classes”NŒ report_level”KŒ halt_level”KŒexit_status_level”KŒdebug”NŒwarning_stream”NŒ traceback”ˆŒinput_encoding”Œ utf-8-sig”Œinput_encoding_error_handler”Œstrict”Œoutput_encoding”Œutf-8”Œoutput_encoding_error_handler”j¹Œerror_encoding”Œutf-8”Œerror_encoding_error_handler”Œbackslashreplace”Œ language_code”Œen”Œrecord_dependencies”NŒconfig”NŒ id_prefix”hŒauto_id_prefix”Œid”Œ dump_settings”NŒdump_internals”NŒdump_transforms”NŒdump_pseudo_xml”NŒexpose_internals”NŒstrict_visitor”NŒ_disable_config”NŒ_source”h¶Œ _destination”NŒ _config_files”]”Œ7/var/lib/git/docbuild/linux/Documentation/docutils.conf”aŒfile_insertion_enabled”ˆŒ raw_enabled”KŒline_length_limit”M'Œpep_references”NŒ pep_base_url”Œhttps://peps.python.org/”Œpep_file_url_template”Œpep-%04d”Œrfc_references”NŒ rfc_base_url”Œ&https://datatracker.ietf.org/doc/html/”Œ tab_width”KŒtrim_footnote_reference_space”‰Œsyntax_highlight”Œlong”Œ smart_quotes”ˆŒsmartquotes_locales”]”Œcharacter_level_inline_markup”‰Œdoctitle_xform”‰Œ docinfo_xform”KŒsectsubtitle_xform”‰Œ image_loading”Œlink”Œembed_stylesheet”‰Œcloak_email_addresses”ˆŒsection_self_link”‰Œenv”NubŒreporter”NŒindirect_targets”]”Œsubstitution_defs”}”Œsubstitution_names”}”Œrefnames”}”Œrefids”}”Œnameids”}”(j“jjQjLjšhüj1jjej@j‹jbjZjjdj£j´jÅj|jçjêj j„j+uŒ nametypes”}”(j“‰jQ‰jš‰j1‰je‰j‹‰jZ‰jd‰j´‰j|‰jê‰j„‰uh}”(jh£jLhÛhüjTjjj@j4jbjhjj‡j£j]jÅjgjçj·j jj+jíhöhíjjj:j1j\jSj{jrjj”j¿j¶jájØjjúj%juŒ footnote_refs”}”Œ citation_refs”}”Œ autofootnotes”]”Œautofootnote_refs”]”Œsymbol_footnotes”]”Œsymbol_footnote_refs”]”Œ footnotes”]”Œ citations”]”Œautofootnote_start”KŒsymbol_footnote_start”KŒ id_counter”Œ collections”ŒCounter”“”}”jÇK s…”R”Œparse_messages”]”Œtransform_messages”]”Œ transformer”NŒ include_log”]”Œ decoration”Nhžhub.