@@ -169,6 +169,51 @@ namespace photon
169169 void * _ptr;
170170 };
171171
172+ #if defined(__has_feature)
173+ # if __has_feature(address_sanitizer) // for clang
174+ # define __SANITIZE_ADDRESS__ // GCC already sets this
175+ # endif
176+ #endif
177+
178+ #ifdef __SANITIZE_ADDRESS__
179+ extern " C" {
180+ // Check out sanitizer/asan-interface.h in compiler-rt for documentation.
181+ void __sanitizer_start_switch_fiber (void ** fake_stack_save, const void * bottom,
182+ size_t size);
183+ void __sanitizer_finish_switch_fiber (void * fake_stack_save,
184+ const void ** bottom_old, size_t * size_old);
185+ }
186+
187+ static void asan_start (void ** save, thread* to) {
188+ void * bottom = to->buf ? to->buf : to->stackful_alloc_top ;
189+ __sanitizer_start_switch_fiber (save, bottom,
190+ to->stack_size );
191+ }
192+
193+ static void asan_finish (void * save) {
194+ __sanitizer_finish_switch_fiber (save, nullptr , nullptr );
195+ }
196+
197+ #define ASAN_START () asan_finish((void *)nullptr );
198+
199+ #define ASAN_SWITCH (to ) \
200+ void * __save; \
201+ asan_start (&__save, to); \
202+ DEFER ({ asan_finish (__save); });
203+
204+ #define ASAN_DIE_SWITCH (to ) \
205+ asan_start (nullptr , to);
206+
207+ #else
208+ #define ASAN_START (ptr )
209+ #define ASAN_SWITCH (to )
210+ #define ASAN_DIE_SWITCH (to )
211+ #endif
212+
213+ static void _asan_start () asm(" _asan_start" );
214+
215+ __attribute__ ((used)) static void _asan_start () { ASAN_START (); }
216+
172217 struct thread_list ;
173218 struct thread : public intrusive_list_node <thread> {
174219 volatile vcpu_t * vcpu;
695740 );
696741
697742 inline void switch_context (thread* from, thread* to) {
743+ ASAN_SWITCH (to);
698744 prepare_switch (from, to);
699745 auto _t_ = to->stack .pointer_ref ();
700746 register auto f asm (" rsi" ) = from->stack .pointer_ref ();
708754
709755 inline void switch_context_defer (thread* from, thread* to,
710756 void (*defer)(void *), void* arg) {
757+ ASAN_SWITCH (to);
711758 prepare_switch (from, to);
712759 auto _t_ = to->stack .pointer_ref ();
713760 register auto f asm (" rcx" ) = from->stack .pointer_ref ();
747794
748795DEF_ASM_FUNC(_photon_thread_stub)
749796R"(
797+ call _asan_start
750798 mov 0x40 (%rbp), %rcx
751799 movq $0, 0x40(%rbp)
752800 call *0x48(%rbp)
757805 );
758806
759807 inline void switch_context (thread* from, thread* to) {
808+ ASAN_SWITCH (to);
760809 prepare_switch (from, to);
761810 auto _t_ = to->stack .pointer_ref ();
762811 register auto f asm (" rdx" ) = from->stack .pointer_ref ();
772821
773822 inline void switch_context_defer (thread* from, thread* to,
774823 void (*defer)(void *), void* arg) {
824+ ASAN_SWITCH (to);
775825 prepare_switch (from, to);
776826 auto _t_ = to->stack .pointer_ref ();
777827 register auto f asm (" r9" ) = from->stack .pointer_ref ();
820870
821871DEF_ASM_FUNC(_photon_thread_stub)
822872R"(
873+ b _asan_start // ; asan_start()
823874 ldp x0, x1, [x29, #0x40 ] // ; load arg, start into x0, x1
824875 str xzr, [x29, #0x40 ] // ; set arg as 0
825876 blr x1 // ; start(x0)
835886#endif
836887
837888 inline void switch_context (thread* from, thread* to) {
889+ ASAN_SWITCH (to);
838890 prepare_switch (from, to);
839891 auto _t_ = to->stack .pointer_ref ();
840892 register auto f asm (" x0" ) = from->stack .pointer_ref ();
854906
855907 inline void switch_context_defer (thread* from, thread* to,
856908 void (*defer)(void *), void* arg) {
909+ ASAN_SWITCH (to);
857910 prepare_switch (from, to);
858911 auto _t_ = to->stack .pointer_ref ();
859912 register auto f asm (" x3" ) = from->stack .pointer_ref ();
899952 func = (uint64_t )&spinlock_unlock;
900953 arg = &lock;
901954 }
955+ ASAN_DIE_SWITCH (sw.to );
902956 _photon_switch_context_defer_die (
903957 arg, func, sw.to ->stack .pointer_ref ());
904958 }
@@ -1943,4 +1997,43 @@ R"(
19431997 photon_thread_alloc = _photon_thread_alloc;
19441998 photon_thread_dealloc = _photon_thread_dealloc;
19451999 }
2000+
2001+ extern " C" {
2002+ [[gnu::used]]
2003+ void *gdb_get_thread_stack_ptr (void *th) {
2004+ if (!th)
2005+ return nullptr ;
2006+ return ((thread *)th)->stack ._ptr ;
2007+ }
2008+ [[gnu::used]]
2009+ void *gdb_get_current_thread () {
2010+ return CURRENT;
2011+ }
2012+ [[gnu::used]]
2013+ void *gdb_get_next_thread (void *c) {
2014+ if (!c)
2015+ return nullptr ;
2016+ return ((thread *)c)->next ();
2017+ }
2018+ [[gnu::used]]
2019+ void *gdb_get_vcpu (void *th) {
2020+ if (!th)
2021+ return nullptr ;
2022+ return (void *)((thread *)th)->vcpu ;
2023+ }
2024+ [[gnu::used]]
2025+ size_t gdb_get_sleepq_size (void *vcpu) {
2026+ if (!vcpu)
2027+ return 0 ;
2028+ return ((vcpu_t *)vcpu)->sleepq .q .size ();
2029+ }
2030+ [[gnu::used]]
2031+ void *gdb_get_sleepq_item (void *vcpu, size_t idx) {
2032+ if (!vcpu)
2033+ return nullptr ;
2034+ if (((vcpu_t *)vcpu)->sleepq .q .size () <= idx)
2035+ return nullptr ;
2036+ return ((vcpu_t *)vcpu)->sleepq .q [idx];
2037+ }
2038+ }
19462039}
0 commit comments