@@ -361,32 +361,302 @@ bool EsrevenAdapter::Quit()
361361
362362std::vector<DebugThread> EsrevenAdapter::GetThreadList ()
363363{
364- return {};
364+ // Return cached data if available
365+ if (m_threadCache.has_value ())
366+ {
367+ std::vector<DebugThread> threads;
368+ for (const auto & cached : m_threadCache.value ())
369+ {
370+ threads.emplace_back (cached.tid , cached.rip );
371+ }
372+ return threads;
373+ }
374+
375+ if (m_isTargetRunning || !m_rspConnector)
376+ return {};
377+
378+ // Use the custom rvn:list-threads packet
379+ auto response = m_rspConnector->TransmitAndReceive (RspData (" rvn:list-threads" ));
380+ std::string jsonStr = response.AsString ();
381+
382+ // Check if we got a valid JSON response
383+ if (jsonStr.empty () || jsonStr[0 ] != ' [' )
384+ return {};
385+
386+ std::vector<ThreadFrameCache> cache;
387+ std::vector<DebugThread> threads;
388+
389+ // Parse JSON array of threads
390+ size_t pos = 0 ;
391+ while (pos < jsonStr.length ())
392+ {
393+ // Find the start of a thread object
394+ size_t threadStart = jsonStr.find (' {' , pos);
395+ if (threadStart == std::string::npos)
396+ break ;
397+
398+ // Find the end of the thread object (handles nested frames array)
399+ int braceCount = 0 ;
400+ size_t threadEnd = threadStart;
401+ for (size_t i = threadStart; i < jsonStr.length (); i++)
402+ {
403+ if (jsonStr[i] == ' {' )
404+ braceCount++;
405+ else if (jsonStr[i] == ' }' )
406+ {
407+ braceCount--;
408+ if (braceCount == 0 )
409+ {
410+ threadEnd = i;
411+ break ;
412+ }
413+ }
414+ }
415+
416+ if (threadEnd == threadStart)
417+ break ;
418+
419+ std::string threadObj = jsonStr.substr (threadStart, threadEnd - threadStart + 1 );
420+
421+ // Parse thread fields
422+ ThreadFrameCache threadData;
423+ threadData.tid = 0 ;
424+ threadData.rip = 0 ;
425+
426+ // Extract "tid"
427+ size_t tidPos = threadObj.find (" \" tid\" " );
428+ if (tidPos != std::string::npos)
429+ {
430+ size_t colonPos = threadObj.find (' :' , tidPos);
431+ if (colonPos != std::string::npos)
432+ {
433+ colonPos++;
434+ while (colonPos < threadObj.length () && std::isspace (threadObj[colonPos]))
435+ colonPos++;
436+
437+ size_t numEnd = colonPos;
438+ while (numEnd < threadObj.length () && std::isdigit (threadObj[numEnd]))
439+ numEnd++;
440+
441+ if (numEnd > colonPos)
442+ {
443+ std::string tidStr = threadObj.substr (colonPos, numEnd - colonPos);
444+ threadData.tid = std::stoull (tidStr);
445+ }
446+ }
447+ }
448+
449+ // Extract "rip"
450+ size_t ripPos = threadObj.find (" \" rip\" " );
451+ if (ripPos != std::string::npos)
452+ {
453+ size_t colonPos = threadObj.find (' :' , ripPos);
454+ if (colonPos != std::string::npos)
455+ {
456+ colonPos++;
457+ while (colonPos < threadObj.length () && std::isspace (threadObj[colonPos]))
458+ colonPos++;
459+
460+ size_t numEnd = colonPos;
461+ while (numEnd < threadObj.length () && std::isdigit (threadObj[numEnd]))
462+ numEnd++;
463+
464+ if (numEnd > colonPos)
465+ {
466+ std::string ripStr = threadObj.substr (colonPos, numEnd - colonPos);
467+ threadData.rip = std::stoull (ripStr);
468+ }
469+ }
470+ }
365471
366- // if (m_isTargetRunning || !m_rspConnector)
367- // return {};
368- //
369- // std::vector<DebugThread> threads{};
370- //
371- // auto reply = this->m_rspConnector->TransmitAndReceive(RspData("qfThreadInfo"));
372- // while(reply.m_data[0] != 'l') {
373- // if (reply.m_data[0] != 'm') {
374- // LogWarn("RSP thread list error");
375- // return threads;
376- // }
377- //
378- // const auto shortened_string =
379- // reply.AsString().substr(1);
380- // const auto tids = RspConnector::Split(shortened_string, ",");
381- // for ( const auto& tid : tids )
382- // threads.emplace_back(std::stoi(tid, nullptr, 16));
383- //
384- // reply = this->m_rspConnector->TransmitAndReceive(RspData("qsThreadInfo"));
385- // }
386- //
387- // return threads;
472+ // Extract "frames" array
473+ size_t framesPos = threadObj.find (" \" frames\" " );
474+ if (framesPos != std::string::npos)
475+ {
476+ size_t arrayStart = threadObj.find (' [' , framesPos);
477+ if (arrayStart != std::string::npos)
478+ {
479+ // Find the matching closing bracket
480+ int bracketCount = 0 ;
481+ size_t arrayEnd = arrayStart;
482+ for (size_t i = arrayStart; i < threadObj.length (); i++)
483+ {
484+ if (threadObj[i] == ' [' )
485+ bracketCount++;
486+ else if (threadObj[i] == ' ]' )
487+ {
488+ bracketCount--;
489+ if (bracketCount == 0 )
490+ {
491+ arrayEnd = i;
492+ break ;
493+ }
494+ }
495+ }
496+
497+ if (arrayEnd > arrayStart)
498+ {
499+ std::string framesArray = threadObj.substr (arrayStart + 1 , arrayEnd - arrayStart - 1 );
500+
501+ // Parse individual frame objects
502+ size_t framePos = 0 ;
503+ while (framePos < framesArray.length ())
504+ {
505+ size_t frameStart = framesArray.find (' {' , framePos);
506+ if (frameStart == std::string::npos)
507+ break ;
508+
509+ int frameBraceCount = 0 ;
510+ size_t frameEnd = frameStart;
511+ for (size_t i = frameStart; i < framesArray.length (); i++)
512+ {
513+ if (framesArray[i] == ' {' )
514+ frameBraceCount++;
515+ else if (framesArray[i] == ' }' )
516+ {
517+ frameBraceCount--;
518+ if (frameBraceCount == 0 )
519+ {
520+ frameEnd = i;
521+ break ;
522+ }
523+ }
524+ }
525+
526+ if (frameEnd == frameStart)
527+ break ;
528+
529+ std::string frameObj = framesArray.substr (frameStart, frameEnd - frameStart + 1 );
530+
531+ // Parse frame fields
532+ DebugFrame frame;
533+ frame.m_index = 0 ;
534+ frame.m_pc = 0 ;
535+ frame.m_sp = 0 ;
536+ frame.m_fp = 0 ;
537+ frame.m_functionName = " " ;
538+ frame.m_functionStart = 0 ;
539+ frame.m_module = " <unknown>" ;
540+
541+ // Helper lambda to extract integer value
542+ auto extractInt = [](const std::string& obj, const std::string& key) -> uint64_t {
543+ size_t keyPos = obj.find (" \" " + key + " \" " );
544+ if (keyPos != std::string::npos)
545+ {
546+ size_t colonPos = obj.find (' :' , keyPos);
547+ if (colonPos != std::string::npos)
548+ {
549+ colonPos++;
550+ while (colonPos < obj.length () && std::isspace (obj[colonPos]))
551+ colonPos++;
552+
553+ // Check for null
554+ if (obj.substr (colonPos, 4 ) == " null" )
555+ return 0 ;
556+
557+ size_t numEnd = colonPos;
558+ while (numEnd < obj.length () && std::isdigit (obj[numEnd]))
559+ numEnd++;
560+
561+ if (numEnd > colonPos)
562+ {
563+ std::string numStr = obj.substr (colonPos, numEnd - colonPos);
564+ return std::stoull (numStr);
565+ }
566+ }
567+ }
568+ return 0 ;
569+ };
570+
571+ // Helper lambda to extract string value
572+ auto extractString = [](const std::string& obj, const std::string& key) -> std::string {
573+ size_t keyPos = obj.find (" \" " + key + " \" " );
574+ if (keyPos != std::string::npos)
575+ {
576+ size_t colonPos = obj.find (' :' , keyPos);
577+ if (colonPos != std::string::npos)
578+ {
579+ size_t quoteStart = obj.find (' "' , colonPos);
580+ if (quoteStart != std::string::npos)
581+ {
582+ size_t quoteEnd = obj.find (' "' , quoteStart + 1 );
583+ if (quoteEnd != std::string::npos)
584+ {
585+ return obj.substr (quoteStart + 1 , quoteEnd - quoteStart - 1 );
586+ }
587+ }
588+ else
589+ {
590+ // Check for null
591+ colonPos++;
592+ while (colonPos < obj.length () && std::isspace (obj[colonPos]))
593+ colonPos++;
594+ if (obj.substr (colonPos, 4 ) == " null" )
595+ return " " ;
596+ }
597+ }
598+ }
599+ return " " ;
600+ };
601+
602+ frame.m_index = extractInt (frameObj, " index" );
603+ frame.m_pc = extractInt (frameObj, " pc" );
604+ frame.m_sp = extractInt (frameObj, " sp" );
605+ frame.m_fp = extractInt (frameObj, " fp" );
606+ frame.m_functionStart = extractInt (frameObj, " function_start" );
607+
608+ std::string funcName = extractString (frameObj, " function_name" );
609+ if (!funcName.empty ())
610+ frame.m_functionName = funcName;
611+
612+ std::string moduleName = extractString (frameObj, " module" );
613+ if (!moduleName.empty ())
614+ frame.m_module = moduleName;
615+
616+ threadData.frames .push_back (frame);
617+ framePos = frameEnd + 1 ;
618+ }
619+ }
620+ }
621+ }
622+
623+ cache.push_back (threadData);
624+ threads.emplace_back (threadData.tid , threadData.rip );
625+ pos = threadEnd + 1 ;
626+ }
627+
628+ // Cache the results
629+ m_threadCache = cache;
630+
631+ return threads;
632+ }
633+
634+
635+ std::vector<DebugFrame> EsrevenAdapter::GetFramesOfThread (std::uint32_t tid)
636+ {
637+ // If cache is empty, call GetThreadList() to populate it
638+ if (!m_threadCache.has_value ())
639+ {
640+ GetThreadList ();
641+ }
642+
643+ // Search for the thread in the cache
644+ if (m_threadCache.has_value ())
645+ {
646+ for (const auto & threadData : m_threadCache.value ())
647+ {
648+ if (threadData.tid == tid)
649+ {
650+ return threadData.frames ;
651+ }
652+ }
653+ }
654+
655+ // Thread not found, return empty vector
656+ return {};
388657}
389658
659+
390660DebugThread EsrevenAdapter::GetActiveThread () const
391661{
392662 // TODO: GetInstructionOffset() should really be const, but changing it requires changes in lots of files,
@@ -1719,6 +1989,7 @@ void EsrevenAdapter::InvalidateCache()
17191989{
17201990 m_regCache.reset ();
17211991 m_moduleCache.reset ();
1992+ m_threadCache.reset ();
17221993}
17231994
17241995
0 commit comments