a zeҦ@s ddlZddlZddlZddlZddlZddlZddlZddlZddlm Z ddl m Z m Z ddZ e \ZZZedkredeeefesedd evrejd kred ed pd edpdvredejejejdZdZddZeZddZed\ZZes2ededej\ZZ de vrbdZ!ee!e "ddZ#e#Z$dZ%e&e j'dGd d!d!ej(Z)Gd"d#d#e)Z*e&e d$Gd%d&d&e)Z+Gd'd(d(e)Z,Gd)d*d*e)Z-Gd+d,d,e)Z.Gd-d.d.e)Z/d/d0Z0e1d1kre2dS)2N)support)findfilepython_is_optimizedc Cszgd}tj|tjtjdd}||\}}Wdn1sF0Y|jr~tdd|d|jd|d|Wntyt d Yn0t d |}|durtd ||t | d t | d fS)N)gdb-nxz --versionT)stdoutstderruniversal_newlineszCommand  z failed with exit code z : stdout=z stderr=zCouldn't find gdb on the pathz ^(?:GNU|HP) gdb.*?\b(\d+)\.(\d+)zunable to parse GDB version: %r) subprocessPopenPIPE communicate returncode ExceptionjoinOSErrorunittestSkipTestresearchintgroup)cmdprocversionrmatchrA/opt/bitninja-python-dojo/embedded/lib/python3.9/test/test_gdb.pyget_gdb_versions.*    r!zFgdb versions before 7.0 didn't support python embedding. Saw %s.%s: %sz3test_gdb only works on source builds at the moment.ZClangdarwinzDtest_gdb doesn't work correctly when python is built with LLVM clangZPGO_PROF_USE_FLAGZxxxZPY_CORE_CFLAGSz&test_gdb is not reliable on PGO buildsz python-gdb.pyZ123cCs4td}|sdS|}d|vo2tdd|DS)NZCFLAGSFz-mcetcss$|]}|do|d VqdS)z-fcf-protection)z=nonez=returnN) startswithendswith).0flagrrr Qs z!cet_protection..) sysconfigget_config_varsplitany)Zcflagsflagsrrr cet_protectionIs r/cOs|rtj}||nd}d}ttfdkr>|ddtf7}tj||tj tj tj |d}|| \}}Wdn1s0Y| dd| ddfS) zRuns gdb in --batch mode with the additional arguments given by *args. Returns its (stdout, stderr) decoded from utf-8 using the replace handler. N)rz--batchrr"z-iexzadd-auto-load-safe-path )stdinrrenvzutf-8replace) osenvironcopyupdategdb_major_versiongdb_minor_versioncheckout_hook_pathr rrrdecode)argsZenv_varsr3Zbase_cmdrouterrrrr run_gdbYs     *r@z9--eval-command=python import sys; print(sys.version_info)z*gdb not built with embedded python support--argszauto-loading has been declinedz3gdb security settings prevent use of custom hooks: cCs>td\}}td|}|s&td|dd}d|vS)Nz+--eval-command=python print(dir(gdb.Frame))z .*\[(.*)\].*z1Unable to parse output from gdb.Frame.select testr z, z'select')r@rrrrrr,)r_mZ gdb_frame_dirrrr gdb_has_frame_selects    rD builtin_idznot useful for PGOc@sHeZdZdZddedddfddZdddZdd Zd d Zd d Z dS) DebuggerTestsz(Test that the debugger can debug Python.NFc Csdd|ddg}ttfdkr&|dg7}|rBtr8|dg7}||7}n |dg7}d d |D}|d tjg7}|t|s|d g7}|r|d |g7}n|r||g7}t|dt i\} } |s| D]} t | tj dqd| vrt ddD]} | | vrt | dq| S)z Run 'python -c SOURCE' under gdb with a breakpoint. Support injecting commands after the breakpoint is reached Returns the stdout from gdb cmds_after_breakpoint: if provided, a list of strings: gdb commands zset breakpoint pending yeszbreak %szset print address offrunr0zset print entry-values nonext backtracecSsg|] }d|qS)z--eval-command=%sr)r'rrrr z1DebuggerTests.get_stack_trace..rAz-Sz-cPYTHONHASHSEED)filez PC not savedzKgdb cannot walk the frame object because the Program Counter is not present)z!(frame information optimized out)z*Unable to read information on python framez found in gdb output)r9r:CET_PROTECTIONsys executableextendr _args_from_interpreter_flagsr@rL splitlinesprintrrr) selfsourcescript breakpointcmds_after_breakpoint import_site ignore_stderrcommandsr=r>r?linepatternrrr get_stack_tracesB          zDebuggerTests.get_stack_tracecCsP|pdg}|j|t||d}td|tj}|sB|d||f|d|fS)Nz backtrace 1)rXrYrZzS#0\s+builtin_id\s+\(self\=.*,\s+v=\s*(.*?)?\)\s+at\s+\S*[A-Za-z]+/[A-Za-z0-9_-]+\.czUnexpected gdb output: %r %sr )r_ BREAKPOINT_FNrrDOTALLfailr)rUrVrYrZ gdb_outputrCrrr get_gdb_reprs  zDebuggerTests.get_gdb_reprcCs |j||d||fddS)z9Ensure that the given "actual" string ends with "exp_end"z%r did not end with %rmsgN) assertTruer&)rUactualZexp_endrrr assertEndsWith!s  zDebuggerTests.assertEndsWithcCs,t||tj}|s(|jd||fddS)Nz%r did not match %rre)rrrarb)rUrhr^rCrrr assertMultilineMatches&sz$DebuggerTests.assertMultilineMatchescCstdS)Nz gdb_sample.py)rrUrrr get_sample_script+szDebuggerTests.get_sample_script)NF) __name__ __module__ __qualname____doc__r`r_rdrirjrlrrrr rFs m $rFc@seZdZddZdPrettyPrintTestscCs|d}|t|vdS)Nid(42))r_rgr`rUrcrrr test_getting_backtrace/s z'PrettyPrintTests.test_getting_backtraceNcCsB|dt|d\}}|s&t|}|||d|||fdS)Nzid()z1%r did not equal expected %r; full output was: %s)rdasciirepr assertEqual)rUvalZexp_reprgdb_reprrcrrr assertGdbRepr3szPrettyPrintTests.assertGdbReprcCs6|d|d|d|d|ddS)z0Verify the pretty-printing of various int values*rilJ)lI5Nr{rkrrr test_int=s     zPrettyPrintTests.test_intcCs"|d|d|ddS)z2Verify the pretty-printing of True, False and NoneTFNr}rkrrr test_singletonsEs  z PrettyPrintTests.test_singletonscCs0|i|ddid|dddddS)z*Verify the pretty-printing of dictionariesfoobarz{'foo': 'bar'}r|)rZdouglasz{'foo': 'bar', 'douglas': 42}Nr}rkrrr test_dictsKs zPrettyPrintTests.test_dictscCs |g|ttddS)z#Verify the pretty-printing of listsN)r{listrangerkrrr test_listsRs zPrettyPrintTests.test_listscCsR|d|d|d|d|d|tddtdDd S) z#Verify the pretty-printing of bytesrKs(And now for something hopefully the sames7string with embedded NUL here and then some more texts7this is a tab: this is a slash-N: this is a slash-R: s!this is byte 255: and byte 128:cSsg|]}|qSrr)r'brrr rJcrKz/PrettyPrintTests.test_bytes..N)r{bytesrrkrrr test_bytesWs      zPrettyPrintTests.test_bytescsxtdd\}}||ss,td|fdd}ddd|d |d |td d S) z-Verify the pretty-printing of unicode stringsz--eval-commandz:python import locale; print(locale.getpreferredencoding())zFunable to determine the preferred encoding of embedded Python in GDB: cs@z|Wn"ty0|t|Yn 0|dSN)encodeUnicodeEncodeErrorr{rv)textencodingrUrr check_reprus  z1PrettyPrintTests.test_strings..check_reprr$z(And now for something hopefully the samez7string with embedded NUL here and then some more textu☠u 文字化けi!N)r@rstrip RuntimeErrorr{chr)rUr>r?rrrr test_stringses$   zPrettyPrintTests.test_stringscCs(|td|dd|ddS)z$Verify the pretty-printing of tuplesz())r z(1,))rrZbazN)r{tuplerkrrr test_tupless zPrettyPrintTests.test_tuplescCsttfdkr|d|td|tdgdtjjsf|tddgd|tgdd |d \}}| |d d S) z"Verify the pretty-printing of setsr"z.pretty-printing of sets needs gdb 7.3 or laterzset()az{'a'}rz {'a', 'b'}r1rz {4, 5, 6}z&s = set(['a','b']) s.remove('a') id(s)z{'b'}N) r9r:skipTestr{setrOr.ignore_environmentrdrxrUrzrcrrr test_setss  zPrettyPrintTests.test_setscCsjttfdkr|d|td|tdgdtjjsf|tddgd|tgdd d S) z(Verify the pretty-printing of frozensetsrz4pretty-printing of frozensets needs gdb 7.3 or laterz frozenset()rzfrozenset({'a'})rzfrozenset({'a', 'b'})rzfrozenset({4, 5, 6})N)r9r:rr{ frozensetrOr.rrkrrr test_frozensetss  z PrettyPrintTests.test_frozensetscCs8|d\}}||d|d\}}||ddS)NzR try: raise RuntimeError("I am an error") except RuntimeError as e: id(e) zRuntimeError('I am an error',)z= try: a = 1 / 0 except ZeroDivisionError as e: id(e) z&ZeroDivisionError('division by zero',)rdrxrrrr test_exceptionssz PrettyPrintTests.test_exceptionscCs0|d\}}td|}|j|d|ddS)z7Verify the pretty-printing of new-style class instancesz8 class Foo: pass foo = Foo() foo.an_int = 42 id(foo)*'Unexpected new-style class rendering %rreNrdrrrgrUrzrcrCrrr test_modern_classs  z"PrettyPrintTests.test_modern_classcCs0|d\}}td|}|j|d|ddS)z$Unexpected gdb representation: %r %s)rdrrrb) rUrVZ corruptionexpreprrYrzrcr^rCrrr assertSanes   zPrettyPrintTests.assertSanecCs&|jdddgd\}}||ddS)z2Ensure that a NULL PyObject* is handled gracefullyrrzset variable v=0rIrZ0x0Nrrrrr test_NULL_ptrszPrettyPrintTests.test_NULL_ptrcCs|dddS)z?Ensure that a PyObject* with NULL ob_type is handled gracefullyrrzset v->ob_type=0Nrrkrrr test_NULL_ob_typesz"PrettyPrintTests.test_NULL_ob_typecCs|jdddddS)zDEnsure that a PyObject* with a corrupt ob_type is handled gracefullyrrzset v->ob_type=0xDEADBEEF42rNrrkrrr test_corrupt_ob_typesz%PrettyPrintTests.test_corrupt_ob_typecCs|jdddddS)zDEnsure that a PyObject* with a type with corrupt tp_flags is handledrrzset v->ob_type->tp_flags=0x0rrNrrkrrr test_corrupt_tp_flags%sz&PrettyPrintTests.test_corrupt_tp_flagscCs|jdddddS)zCEnsure that a PyObject* with a type with corrupt tp_name is handledrrz"set v->ob_type->tp_name=0xDEADBEEFrrNrrkrrr test_corrupt_tp_name+sz%PrettyPrintTests.test_corrupt_tp_namecCsFtjjr|d|jddd\}}td|}|j|d|ddS) zAEnsure that the new-style class _Helper in site.py can be handledz(need site module, but -S option was usedzid(__builtins__.help)T)rZz!<_Helper at remote 0x-?[0-9a-f]+>zUnexpected rendering %rreN)rOr.no_siterrdrrrgrrrr test_builtins_help1s  z#PrettyPrintTests.test_builtins_helpcCs8|d\}}||d|d\}}||ddS)zbEnsure that a reference loop involving a list doesn't lead proxyval into an infinite loop:z#a = [3, 4, 5] ; a.append(a) ; id(a)z[3, 4, 5, [...]]z-a = [3, 4, 5] ; b = [a] ; a.append(b) ; id(a)z[3, 4, 5, [[...]]]Nrrrrr test_selfreferential_list?s  z*PrettyPrintTests.test_selfreferential_listcCs|d\}}||ddS)zbEnsure that a reference loop involving a dict doesn't lead proxyval into an infinite loop:z-a = {} ; b = {'bar':a} ; a['foo'] = b ; id(a)z{'foo': {'bar': {...}}}Nrrrrr test_selfreferential_dictJsz*PrettyPrintTests.test_selfreferential_dictcCs.|d\}}|td|d||fdS)Nz: class Foo: pass foo = Foo() foo.an_attr = foo id(foo)1\) at remote 0x-?[0-9a-f]+>rrdrgrrrrrr 'test_selfreferential_old_style_instanceRs z8PrettyPrintTests.test_selfreferential_old_style_instancecCsX|d\}}|td|d||f|d\}}|td|d||fdS)NzB class Foo(object): pass foo = Foo() foo.an_attr = foo id(foo)rrzR class Foo(object): pass a = Foo() b = Foo() a.an_attr = b b.an_attr = a id(a)zZ\) at remote 0x-?[0-9a-f]+>\) at remote 0x-?[0-9a-f]+>rrrrr 'test_selfreferential_new_style_instance_s$  z8PrettyPrintTests.test_selfreferential_new_style_instancecCs6|d\}}||d|t|dtddS)z)Verify that very long output is truncatedzid(list(range(1000)))a[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226...(truncated)iz...(truncated)N)rdrxlenrrrr test_truncationzs  z PrettyPrintTests.test_truncationcCs.|d\}}|td|d||fdS)Nz$import sys; id(sys.stdout.readlines)zOrrrrrr test_builtin_methods z$PrettyPrintTests.test_builtin_methodcCs6|jdddgd}|td|tjd||fdS)Nz: def foo(a, b, c): pass foo(3, 4, 5) id(foo.__code__)rEz:print (PyFrameObject*)(((PyCodeObject*)v)->co_zombieframe))rXrYzM.*\s+\$1 =\s+Frame 0x-?[0-9a-f]+, for file , line 3, in foo \(\)\s+.*r)r_rgrrrarsrrr test_framess  zPrettyPrintTests.test_frames)N)N) rmrnrortr{r~rrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rq.s: ,      rq&Python was compiled with optimizationsc@s,eZdZddZddZddZddZd S) PyListTestscCs|||dSr)ri)rUZexpectedrhrrr assertListingszPyListTests.assertListingcCs$|j|dgd}|d|dS)z'Verify that the "py-list" command workszpy-listrWrYz 5 6 def bar(a, b, c): 7 baz(a, b, c) 8 9 def baz(*args): >10 id(42) 11 12 foo(1, 2, 3) Nr_rlrrUbtrrr test_basic_commands  zPyListTests.test_basic_commandcCs$|j|dgd}|d|dS)z7Verify the "py-list" command with one absolute argumentz py-list 9rzI 9 def baz(*args): >10 id(42) 11 12 foo(1, 2, 3) Nrrrrr test_one_abs_args  zPyListTests.test_one_abs_argcCs$|j|dgd}|d|dS)z8Verify the "py-list" command with two absolute argumentsz py-list 1,3rzR 1 # Sample script for use by test_gdb.py 2 3 def foo(a, b, c): Nrrrrr test_two_abs_argss  zPyListTests.test_two_abs_argsN)rmrnrorrrrrrrr rs rc@sxeZdZeedeedddZeedddZ eedddZ eedeedd d Z d S) StackNavigationTests$test requires py-up/py-down commandsrcCs&|j|ddgd}||ddS)z%Verify that the "py-up" command workspy-uprzp^.* #[0-9]+ Frame 0x-?[0-9a-f]+, for file .*gdb_sample.py, line 7, in bar \(a=1, b=2, c=3\) baz\(a, b, c\) $Nr_rlrjrrrr test_pyup_commands  z&StackNavigationTests.test_pyup_commandcCs$|j|dgd}||ddS)z7Verify handling of "py-down" at the bottom of the stackpy-downrz$Unable to find a newer python frame Nr_rlrirrrr test_down_at_bottoms  z(StackNavigationTests.test_down_at_bottomcCs(|j|dgdd}||ddS)z2Verify handling of "py-up" at the top of the stackrrrz%Unable to find an older python frame Nrrrrr test_up_at_tops  z#StackNavigationTests.test_up_at_topcCs&|j|gdd}||ddS)z$Verify "py-up" followed by "py-down")rrrrz^.* #[0-9]+ Frame 0x-?[0-9a-f]+, for file .*gdb_sample.py, line 7, in bar \(a=1, b=2, c=3\) baz\(a, b, c\) #[0-9]+ Frame 0x-?[0-9a-f]+, for file .*gdb_sample.py, line 10, in baz \(args=\(1, 2, 3\)\) id\(42\) $Nrrrrr test_up_then_downs  z&StackNavigationTests.test_up_then_downN) rmrnror skipUnlessHAS_PYUP_PYDOWNskipIfrrrrrrrrr rs      rc@seZdZeedddZeedddZddZeeddd Z eedd d Z eedd d Z dS) PyBtTestsrcCs$|j|dgd}||ddS)z%Verify that the "py-bt" command workspy-btraF^.* Traceback \(most recent call first\): File ".*gdb_sample.py", line 10, in baz id\(42\) File ".*gdb_sample.py", line 7, in bar baz\(a, b, c\) File ".*gdb_sample.py", line 4, in foo bar\(a, b, c\) File ".*gdb_sample.py", line 12, in foo\(1, 2, 3\) Nrrrrr test_bts  zPyBtTests.test_btcCs$|j|dgd}||ddS)z*Verify that the "py-bt-full" command works py-bt-fullra>^.* #[0-9]+ Frame 0x-?[0-9a-f]+, for file .*gdb_sample.py, line 7, in bar \(a=1, b=2, c=3\) baz\(a, b, c\) #[0-9]+ Frame 0x-?[0-9a-f]+, for file .*gdb_sample.py, line 4, in foo \(a=1, b=2, c=3\) bar\(a, b, c\) #[0-9]+ Frame 0x-?[0-9a-f]+, for file .*gdb_sample.py, line 12, in \(\) foo\(1, 2, 3\) Nrrrrr test_bt_fulls  zPyBtTests.test_bt_fullcCs@d}|j|dgd}|d||j|dgd}|d|dS)zBVerify that "py-bt" indicates threads that are waiting for the GILaN from threading import Thread class TestThread(Thread): # These threads would run forever, but we'll interrupt things with the # debugger def run(self): i = 0 while 1: i += 1 t = {} for i in range(4): t[i] = TestThread() t[i].start() # Trigger a breakpoint on the main thread id(42) zthread apply all py-btrzWaiting for the GILzthread apply all py-bt-fullNr_assertInrUrrcrrr test_threads(s zPyBtTests.test_threadscCsDd}|j|gdd}|d||j|gdd}|d|dS)z?Verify that "py-bt" indicates if a thread is garbage-collectingzRfrom gc import collect id(42) def foo(): collect() def bar(): foo() bar() )break update_refscontinuerrzGarbage-collecting)rrrNrrrrr test_gcHs zPyBtTests.test_gcc CsdD]\}}}dD]}||d|td|d|d|d}|j||ddgd d }|d |||j||d gd d }|d |d||Wdq1s0YqqdS)zAVerify that "py-bt" displays invocations of PyCFunction instances))Z meth_varargsr$r )Zmeth_varargs_keywordsr$r )Zmeth_oz[]r )Z meth_noargsr$r )Z meth_fastcallr$r )Zmeth_fastcall_keywordsr$r )Z _testcapiz_testcapi.MethClassz_testcapi.MethClass()z_testcapi.MethStatic().zi import _testcapi def foo(): (zy) def bar(): foo() bar() rrT)rXrYr[z\n.*rrrrr test_printing_builtins  z"PyPrintTests.test_printing_builtinN) rmrnrorrrrrrrrrrrrr rs"    rc@sDeZdZeedddZeedeedddZ dS) PyLocalsTestsrcCs&|j|ddgd}||ddS)Nr py-localsrz.*\nargs = \(1, 2, 3\)\n.*rrrrr rs  z PyLocalsTests.test_basic_commandrcCs&|j|gdd}||ddS)N)rrrrz.*\na = 1\nb = 2\nc = 3\n.*rrrrr test_locals_after_ups  z"PyLocalsTests.test_locals_after_upN) rmrnrorrrrrrrrrrr rs  rcCs4tjr0tdttftD]}td|qdS)NzGDB version %s.%s:z )rverboserTr9r: gdb_versionrS)r]rrr setUpModules r__main__)3r5platformrr rOr*rrtestrZ test.supportrrr!rr9r:rZis_python_buildZpython_compilerr+pathrdirnamerPr;rLr/rNr@Z gdbpy_versionrBZ gdbpy_errorsrfrrDrr`rZPGOZTestCaserFrqrrrrrrrmmainrrrr sz             "(-=#