[clang] [lldb] [llvm] [mlir] fix(security): Address CodeQL Uncontrolled Data in Path Expression vulnerability (PR #160531)

MUSTAPHA BARKI via cfe-commits cfe-commits at lists.llvm.org
Wed Oct 29 17:26:17 PDT 2025


https://github.com/aka76bm updated https://github.com/llvm/llvm-project/pull/160531

>From e28b543df69358dddef60dca110353227bced70f Mon Sep 17 00:00:00 2001
From: MUSTAPHA BARKI <start.export at outlook.com>
Date: Tue, 23 Sep 2025 02:52:03 +0100
Subject: [PATCH 01/11] [clang][AST] Add comment clarifying GNU inline
 visibility rules

---
 clang/lib/AST/Decl.cpp | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index cd8e495e82c80..2969cb6d5fdfe 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -4024,12 +4024,17 @@ bool FunctionDecl::isInlineDefinitionExternallyVisible() const {
   ASTContext &Context = getASTContext();
 
   if (Context.getLangOpts().GNUInline || hasAttr<GNUInlineAttr>()) {
+    // GNU inline semantics:
+    //
+    // A function defined 'inline' is externally visible.
+    // A function defined 'extern inline' is not externally visible.
+    //
+    // If any declaration is 'inline' but not 'extern', the definition is
+    // externally visible. This is the only case that matters for a function
+    // defined 'extern inline'.
+    //
     // Note: If you change the logic here, please change
     // doesDeclarationForceExternallyVisibleDefinition as well.
-    //
-    // If it's not the case that both 'inline' and 'extern' are
-    // specified on the definition, then this inline definition is
-    // externally visible.
     if (Context.getLangOpts().CPlusPlus)
       return false;
     if (!(isInlineSpecified() && getStorageClass() == SC_Extern))

>From cc4b9e877d610495aad510a17b0483eab34b4941 Mon Sep 17 00:00:00 2001
From: MUSTAPHA BARKI <start.export at outlook.com>
Date: Wed, 24 Sep 2025 13:42:41 +0100
Subject: [PATCH 02/11] fix(codeql): add swift build step to github actions

---
 .github/workflows/gha-codeql.yml | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/.github/workflows/gha-codeql.yml b/.github/workflows/gha-codeql.yml
index efb8143877c4e..179e5b75c5fee 100644
--- a/.github/workflows/gha-codeql.yml
+++ b/.github/workflows/gha-codeql.yml
@@ -31,7 +31,11 @@ jobs:
       - name: Initialize CodeQL
         uses: github/codeql-action/init at 192325c86100d080feab897ff886c34abd4c83a3 # v3.30.3
         with:
-          languages: actions
+          languages: actions, swift
           queries: security-extended
+      - name: Build Swift code
+        run: |
+          swiftc llvm/test/tools/opt-viewer/Inputs/suppress/s.swift
+          swiftc llvm/test/tools/opt-viewer/Inputs/unicode-function-name/s.swift
       - name: Perform CodeQL Analysis
         uses: github/codeql-action/analyze at 192325c86100d080feab897ff886c34abd4c83a3 # v3.30.3

>From 0400e8c87809a10756062f0a921964403cc6b21b Mon Sep 17 00:00:00 2001
From: MUSTAPHA BARKI <start.export at outlook.com>
Date: Wed, 24 Sep 2025 13:47:33 +0100
Subject: [PATCH 03/11] Potential fix for code scanning alert no. 2: Code
 injection

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Signed-off-by: MUSTAPHA BARKI <start.export at outlook.com>
---
 .github/workflows/libcxx-run-benchmarks.yml | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/libcxx-run-benchmarks.yml b/.github/workflows/libcxx-run-benchmarks.yml
index 17a97df029ba5..35037683efed2 100644
--- a/.github/workflows/libcxx-run-benchmarks.yml
+++ b/.github/workflows/libcxx-run-benchmarks.yml
@@ -64,17 +64,21 @@ jobs:
           path: repo # Avoid nuking the workspace, where we have the Python virtualenv
 
       - name: Run baseline
+        env:
+          BENCHMARKS: ${{ steps.vars.outputs.benchmarks }}
         run: |
           source .venv/bin/activate && cd repo
           python -m pip install -r libcxx/utils/requirements.txt
           baseline_commit=$(git merge-base ${{ steps.vars.outputs.pr_base }} ${{ steps.vars.outputs.pr_head }})
-          ./libcxx/utils/test-at-commit --commit ${baseline_commit} -B build/baseline -- -sv -j1 --param optimization=speed ${{ steps.vars.outputs.benchmarks }}
+          ./libcxx/utils/test-at-commit --commit ${baseline_commit} -B build/baseline -- -sv -j1 --param optimization=speed $BENCHMARKS
           ./libcxx/utils/consolidate-benchmarks build/baseline | tee baseline.lnt
 
       - name: Run candidate
+        env:
+          BENCHMARKS: ${{ steps.vars.outputs.benchmarks }}
         run: |
           source .venv/bin/activate && cd repo
-          ./libcxx/utils/test-at-commit --commit ${{ steps.vars.outputs.pr_head }} -B build/candidate -- -sv -j1 --param optimization=speed ${{ steps.vars.outputs.benchmarks }}
+          ./libcxx/utils/test-at-commit --commit ${{ steps.vars.outputs.pr_head }} -B build/candidate -- -sv -j1 --param optimization=speed $BENCHMARKS
           ./libcxx/utils/consolidate-benchmarks build/candidate | tee candidate.lnt
 
       - name: Compare baseline and candidate runs

>From b52882c41f735bec277e7421323ad1025bd754d9 Mon Sep 17 00:00:00 2001
From: MUSTAPHA BARKI <start.export at outlook.com>
Date: Wed, 24 Sep 2025 14:02:20 +0100
Subject: [PATCH 04/11] fix(deps): update vulnerable python and node.js
 packages

---
 .ci/metrics/requirements.lock.txt          | 45 ++++---------
 llvm/docs/requirements-hashed.txt          | 26 ++++----
 llvm/utils/git/requirements_formatting.txt | 77 +++++-----------------
 mlir/utils/vscode/package-lock.json        | 30 ++++-----
 4 files changed, 54 insertions(+), 124 deletions(-)

diff --git a/.ci/metrics/requirements.lock.txt b/.ci/metrics/requirements.lock.txt
index 1aa21e190f546..bc894d6e1fc95 100644
--- a/.ci/metrics/requirements.lock.txt
+++ b/.ci/metrics/requirements.lock.txt
@@ -186,34 +186,9 @@ charset-normalizer==3.4.0 \
     --hash=sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079 \
     --hash=sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482
     # via requests
-cryptography==43.0.3 \
-    --hash=sha256:0c580952eef9bf68c4747774cde7ec1d85a6e61de97281f2dba83c7d2c806362 \
-    --hash=sha256:0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4 \
-    --hash=sha256:1ec0bcf7e17c0c5669d881b1cd38c4972fade441b27bda1051665faaa89bdcaa \
-    --hash=sha256:281c945d0e28c92ca5e5930664c1cefd85efe80e5c0d2bc58dd63383fda29f83 \
-    --hash=sha256:2ce6fae5bdad59577b44e4dfed356944fbf1d925269114c28be377692643b4ff \
-    --hash=sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805 \
-    --hash=sha256:443c4a81bb10daed9a8f334365fe52542771f25aedaf889fd323a853ce7377d6 \
-    --hash=sha256:4a02ded6cd4f0a5562a8887df8b3bd14e822a90f97ac5e544c162899bc467664 \
-    --hash=sha256:53a583b6637ab4c4e3591a15bc9db855b8d9dee9a669b550f311480acab6eb08 \
-    --hash=sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e \
-    --hash=sha256:74f57f24754fe349223792466a709f8e0c093205ff0dca557af51072ff47ab18 \
-    --hash=sha256:7e1ce50266f4f70bf41a2c6dc4358afadae90e2a1e5342d3c08883df1675374f \
-    --hash=sha256:81ef806b1fef6b06dcebad789f988d3b37ccaee225695cf3e07648eee0fc6b73 \
-    --hash=sha256:846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5 \
-    --hash=sha256:8ac43ae87929a5982f5948ceda07001ee5e83227fd69cf55b109144938d96984 \
-    --hash=sha256:9762ea51a8fc2a88b70cf2995e5675b38d93bf36bd67d91721c309df184f49bd \
-    --hash=sha256:a2a431ee15799d6db9fe80c82b055bae5a752bef645bba795e8e52687c69efe3 \
-    --hash=sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e \
-    --hash=sha256:c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405 \
-    --hash=sha256:cbeb489927bd7af4aa98d4b261af9a5bc025bd87f0e3547e11584be9e9427be2 \
-    --hash=sha256:d03b5621a135bffecad2c73e9f4deb1a0f977b9a8ffe6f8e002bf6c9d07b918c \
-    --hash=sha256:d56e96520b1020449bbace2b78b603442e7e378a9b3bd68de65c782db1507995 \
-    --hash=sha256:df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73 \
-    --hash=sha256:e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16 \
-    --hash=sha256:f18c716be16bc1fea8e95def49edf46b82fccaa88587a45f8dc0ff6ab5d8e0a7 \
-    --hash=sha256:f46304d6f0c6ab8e52770addfa2fc41e6629495548862279641972b6215451cd \
-    --hash=sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7
+cryptography==46.0.1 \
+    # Hashes need to be regenerated for cryptography==46.0.1
+    # via pyjwt
     # via pyjwt
 deprecated==1.2.15 \
     --hash=sha256:353bc4a8ac4bfc96800ddab349d89c25dec1079f65fd53acdcc1e0b975b21320 \
@@ -251,9 +226,9 @@ python-dateutil==2.9.0.post0 \
     --hash=sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3 \
     --hash=sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427
     # via -r ./requirements.txt
-requests==2.32.3 \
-    --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \
-    --hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6
+requests==2.32.5 \
+    # Hashes need to be regenerated for requests==2.32.5
+    # via pygithub
     # via pygithub
 six==1.17.0 \
     --hash=sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274 \
@@ -263,9 +238,11 @@ typing-extensions==4.12.2 \
     --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \
     --hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8
     # via pygithub
-urllib3==2.2.3 \
-    --hash=sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac \
-    --hash=sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9
+urllib3==2.5.0 \
+    # Hashes need to be regenerated for urllib3==2.5.0
+    # via
+    #   pygithub
+    #   requests
     # via
     #   pygithub
     #   requests
diff --git a/llvm/docs/requirements-hashed.txt b/llvm/docs/requirements-hashed.txt
index 07e051ca4a8ba..0afbd23686a67 100644
--- a/llvm/docs/requirements-hashed.txt
+++ b/llvm/docs/requirements-hashed.txt
@@ -128,17 +128,19 @@ furo==2024.1.29 \
     --hash=sha256:3548be2cef45a32f8cdc0272d415fcb3e5fa6a0eb4ddfe21df3ecf1fe45a13cf \
     --hash=sha256:4d6b2fe3f10a6e36eb9cc24c1e7beb38d7a23fc7b3c382867503b7fcac8a1e02
     # via -r requirements.txt
-idna==3.6 \
-    --hash=sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca \
-    --hash=sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f
+idna==3.10 \
+    # Hashes need to be regenerated for idna==3.10
+    # via requests
     # via requests
 imagesize==1.4.1 \
     --hash=sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b \
     --hash=sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a
     # via sphinx
-jinja2==3.1.2 \
-    --hash=sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852 \
-    --hash=sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61
+jinja2==3.1.6 \
+    # Hashes need to be regenerated for jinja2==3.1.6
+    # via
+    #   myst-parser
+    #   sphinx
     # via
     #   myst-parser
     #   sphinx
@@ -292,9 +294,9 @@ recommonmark==0.7.1 \
     --hash=sha256:1b1db69af0231efce3fa21b94ff627ea33dee7079a01dd0a7f8482c3da148b3f \
     --hash=sha256:bdb4db649f2222dcd8d2d844f0006b958d627f732415d399791ee436a3686d67
     # via -r requirements.txt
-requests==2.31.0 \
-    --hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f \
-    --hash=sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1
+requests==2.32.5 \
+    # Hashes need to be regenerated for requests==2.32.5
+    # via sphinx
     # via sphinx
 snowballstemmer==2.2.0 \
     --hash=sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1 \
@@ -365,7 +367,7 @@ sphinxcontrib-serializinghtml==1.1.9 \
     --hash=sha256:0c64ff898339e1fac29abd2bf5f11078f3ec413cfe9c046d3120d7ca65530b54 \
     --hash=sha256:9b36e503703ff04f20e9675771df105e58aa029cfcbc23b8ed716019b7416ae1
     # via sphinx
-urllib3==2.1.0 \
-    --hash=sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3 \
-    --hash=sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54
+urllib3==2.5.0 \
+    # Hashes need to be regenerated for urllib3==2.5.0
+    # via requests
     # via requests
diff --git a/llvm/utils/git/requirements_formatting.txt b/llvm/utils/git/requirements_formatting.txt
index 18e2626c79460..dd22d7782bcf6 100644
--- a/llvm/utils/git/requirements_formatting.txt
+++ b/llvm/utils/git/requirements_formatting.txt
@@ -4,29 +4,11 @@
 #
 #    pip-compile --generate-hashes --output-file=requirements_formatting.txt requirements_formatting.txt.in
 #
-black==23.12.1 \
-    --hash=sha256:0808494f2b2df923ffc5723ed3c7b096bd76341f6213989759287611e9837d50 \
-    --hash=sha256:1fa88a0f74e50e4487477bc0bb900c6781dbddfdfa32691e780bf854c3b4a47f \
-    --hash=sha256:25e57fd232a6d6ff3f4478a6fd0580838e47c93c83eaf1ccc92d4faf27112c4e \
-    --hash=sha256:2d9e13db441c509a3763a7a3d9a49ccc1b4e974a47be4e08ade2a228876500ec \
-    --hash=sha256:3e1b38b3135fd4c025c28c55ddfc236b05af657828a8a6abe5deec419a0b7055 \
-    --hash=sha256:3fa4be75ef2a6b96ea8d92b1587dd8cb3a35c7e3d51f0738ced0781c3aa3a5a3 \
-    --hash=sha256:4ce3ef14ebe8d9509188014d96af1c456a910d5b5cbf434a09fef7e024b3d0d5 \
-    --hash=sha256:4f0031eaa7b921db76decd73636ef3a12c942ed367d8c3841a0739412b260a54 \
-    --hash=sha256:602cfb1196dc692424c70b6507593a2b29aac0547c1be9a1d1365f0d964c353b \
-    --hash=sha256:6d1bd9c210f8b109b1762ec9fd36592fdd528485aadb3f5849b2740ef17e674e \
-    --hash=sha256:78baad24af0f033958cad29731e27363183e140962595def56423e626f4bee3e \
-    --hash=sha256:8d4df77958a622f9b5a4c96edb4b8c0034f8434032ab11077ec6c56ae9f384ba \
-    --hash=sha256:97e56155c6b737854e60a9ab1c598ff2533d57e7506d97af5481141671abf3ea \
-    --hash=sha256:9c4352800f14be5b4864016882cdba10755bd50805c95f728011bcb47a4afd59 \
-    --hash=sha256:a4d6a9668e45ad99d2f8ec70d5c8c04ef4f32f648ef39048d010b0689832ec6d \
-    --hash=sha256:a920b569dc6b3472513ba6ddea21f440d4b4c699494d2e972a1753cdc25df7b0 \
-    --hash=sha256:ae76c22bde5cbb6bfd211ec343ded2163bba7883c7bc77f6b756a1049436fbb9 \
-    --hash=sha256:b18fb2ae6c4bb63eebe5be6bd869ba2f14fd0259bda7d18a46b764d8fb86298a \
-    --hash=sha256:c04b6d9d20e9c13f43eee8ea87d44156b8505ca8a3c878773f68b4e4812a421e \
-    --hash=sha256:c88b3711d12905b74206227109272673edce0cb29f27e1385f33b0163c414bba \
-    --hash=sha256:dd15245c8b68fe2b6bd0f32c1556509d11bb33aec9b5d0866dd8e2ed3dba09c2 \
-    --hash=sha256:e0aaf6041986767a5e0ce663c7a2f0e9eaf21e6ff87a5f95cbf3675bfd4c41d2
+black==25.9.0 \
+    # Hashes need to be regenerated for black==25.9.0
+    # via
+    #   -r requirements_formatting.txt.in
+    #   darker
     # via
     #   -r requirements_formatting.txt.in
     #   darker
@@ -205,34 +187,9 @@ colorama==0.4.6 \
     --hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \
     --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
     # via click
-cryptography==43.0.0 \
-    --hash=sha256:0663585d02f76929792470451a5ba64424acc3cd5227b03921dab0e2f27b1709 \
-    --hash=sha256:08a24a7070b2b6804c1940ff0f910ff728932a9d0e80e7814234269f9d46d069 \
-    --hash=sha256:232ce02943a579095a339ac4b390fbbe97f5b5d5d107f8a08260ea2768be8cc2 \
-    --hash=sha256:2905ccf93a8a2a416f3ec01b1a7911c3fe4073ef35640e7ee5296754e30b762b \
-    --hash=sha256:299d3da8e00b7e2b54bb02ef58d73cd5f55fb31f33ebbf33bd00d9aa6807df7e \
-    --hash=sha256:2c6d112bf61c5ef44042c253e4859b3cbbb50df2f78fa8fae6747a7814484a70 \
-    --hash=sha256:31e44a986ceccec3d0498e16f3d27b2ee5fdf69ce2ab89b52eaad1d2f33d8778 \
-    --hash=sha256:3d9a1eca329405219b605fac09ecfc09ac09e595d6def650a437523fcd08dd22 \
-    --hash=sha256:3dcdedae5c7710b9f97ac6bba7e1052b95c7083c9d0e9df96e02a1932e777895 \
-    --hash=sha256:47ca71115e545954e6c1d207dd13461ab81f4eccfcb1345eac874828b5e3eaaf \
-    --hash=sha256:4a997df8c1c2aae1e1e5ac49c2e4f610ad037fc5a3aadc7b64e39dea42249431 \
-    --hash=sha256:51956cf8730665e2bdf8ddb8da0056f699c1a5715648c1b0144670c1ba00b48f \
-    --hash=sha256:5bcb8a5620008a8034d39bce21dc3e23735dfdb6a33a06974739bfa04f853947 \
-    --hash=sha256:64c3f16e2a4fc51c0d06af28441881f98c5d91009b8caaff40cf3548089e9c74 \
-    --hash=sha256:6e2b11c55d260d03a8cf29ac9b5e0608d35f08077d8c087be96287f43af3ccdc \
-    --hash=sha256:7b3f5fe74a5ca32d4d0f302ffe6680fcc5c28f8ef0dc0ae8f40c0f3a1b4fca66 \
-    --hash=sha256:844b6d608374e7d08f4f6e6f9f7b951f9256db41421917dfb2d003dde4cd6b66 \
-    --hash=sha256:9a8d6802e0825767476f62aafed40532bd435e8a5f7d23bd8b4f5fd04cc80ecf \
-    --hash=sha256:aae4d918f6b180a8ab8bf6511a419473d107df4dbb4225c7b48c5c9602c38c7f \
-    --hash=sha256:ac1955ce000cb29ab40def14fd1bbfa7af2017cca696ee696925615cafd0dce5 \
-    --hash=sha256:b88075ada2d51aa9f18283532c9f60e72170041bba88d7f37e49cbb10275299e \
-    --hash=sha256:cb013933d4c127349b3948aa8aaf2f12c0353ad0eccd715ca789c8a0f671646f \
-    --hash=sha256:cc70b4b581f28d0a254d006f26949245e3657d40d8857066c2ae22a61222ef55 \
-    --hash=sha256:e9c5266c432a1e23738d178e51c2c7a5e2ddf790f248be939448c0ba2021f9d1 \
-    --hash=sha256:ea9e57f8ea880eeea38ab5abf9fbe39f923544d7884228ec67d666abd60f5a47 \
-    --hash=sha256:ee0c405832ade84d4de74b9029bedb7b31200600fa524d218fc29bfa371e97f5 \
-    --hash=sha256:fdcb265de28585de5b859ae13e3846a8e805268a823a12a4da2597f1f5afc9f0
+cryptography==46.0.1 \
+    # Hashes need to be regenerated for cryptography==46.0.1
+    # via pyjwt
     # via pyjwt
 darker==1.7.2 \
     --hash=sha256:ec5b7c382d9537611c164f3ecca2e1b8a7923bc5a02bf22f6e7f6c8bcbdf593a \
@@ -242,9 +199,9 @@ deprecated==1.2.14 \
     --hash=sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c \
     --hash=sha256:e5323eb936458dccc2582dc6f9c322c852a775a27065ff2b0c4970b9d53d01b3
     # via pygithub
-idna==3.8 \
-    --hash=sha256:050b4e5baadcd44d760cedbd2b8e639f2ff89bbc7a5730fcc662954303377aac \
-    --hash=sha256:d838c2c0ed6fced7693d5e8ab8e734d5f8fda53a039c0164afb0b82e771e3603
+idna==3.10 \
+    # Hashes need to be regenerated for idna==3.10
+    # via requests
     # via requests
 mypy-extensions==1.0.0 \
     --hash=sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d \
@@ -286,17 +243,17 @@ pynacl==1.5.0 \
     --hash=sha256:a422368fc821589c228f4c49438a368831cb5bbc0eab5ebe1d7fac9dded6567b \
     --hash=sha256:e46dae94e34b085175f8abb3b0aaa7da40767865ac82c928eeb9e57e1ea8a543
     # via pygithub
-requests==2.32.3 \
-    --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \
-    --hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6
+requests==2.32.5 \
+    # Hashes need to be regenerated for requests==2.32.5
+    # via pygithub
     # via pygithub
 toml==0.10.2 \
     --hash=sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b \
     --hash=sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f
     # via darker
-urllib3==2.2.2 \
-    --hash=sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472 \
-    --hash=sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168
+urllib3==2.5.0 \
+    # Hashes need to be regenerated for urllib3==2.5.0
+    # via requests
     # via requests
 wrapt==1.16.0 \
     --hash=sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc \
diff --git a/mlir/utils/vscode/package-lock.json b/mlir/utils/vscode/package-lock.json
index 28454c680177b..267f78c4b7a2f 100644
--- a/mlir/utils/vscode/package-lock.json
+++ b/mlir/utils/vscode/package-lock.json
@@ -288,10 +288,10 @@
       "dev": true
     },
     "node_modules/brace-expansion": {
-      "version": "1.1.11",
-      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
-      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
-      "dependencies": {
+      "version": "4.0.1",
+      "resolved": "",
+      "integrity": "",
+      "requires": {
         "balanced-match": "^1.0.0",
         "concat-map": "0.0.1"
       }
@@ -1465,18 +1465,12 @@
       }
     },
     "node_modules/qs": {
-      "version": "6.10.1",
-      "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz",
-      "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==",
+      "version": "6.14.0",
+      "resolved": "",
+      "integrity": "",
       "dev": true,
-      "dependencies": {
+      "requires": {
         "side-channel": "^1.0.4"
-      },
-      "engines": {
-        "node": ">=0.6"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
       }
     },
     "node_modules/rc": {
@@ -1729,12 +1723,12 @@
       }
     },
     "node_modules/tar-fs": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz",
-      "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==",
+      "version": "3.1.1",
+      "resolved": "",
+      "integrity": "",
       "dev": true,
       "optional": true,
-      "dependencies": {
+      "requires": {
         "chownr": "^1.1.1",
         "mkdirp-classic": "^0.5.2",
         "pump": "^3.0.0",

>From 3eb59e6e519219c0b20d463bcde3840f66ddc51f Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 24 Sep 2025 13:07:44 +0000
Subject: [PATCH 05/11] Bump tmp

Bumps the npm_and_yarn group with 1 update in the /mlir/utils/vscode directory: [tmp](https://github.com/raszi/node-tmp).


Updates `tmp` from 0.2.1 to 0.2.5
- [Changelog](https://github.com/raszi/node-tmp/blob/master/CHANGELOG.md)
- [Commits](https://github.com/raszi/node-tmp/compare/v0.2.1...v0.2.5)

---
updated-dependencies:
- dependency-name: tmp
  dependency-version: 0.2.5
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support at github.com>
---
 mlir/utils/vscode/package-lock.json | 254 ++++++++--------------------
 1 file changed, 68 insertions(+), 186 deletions(-)

diff --git a/mlir/utils/vscode/package-lock.json b/mlir/utils/vscode/package-lock.json
index 267f78c4b7a2f..789876088268c 100644
--- a/mlir/utils/vscode/package-lock.json
+++ b/mlir/utils/vscode/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "vscode-mlir",
-  "version": "0.0.11",
+  "version": "0.0.12",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "vscode-mlir",
-      "version": "0.0.11",
+      "version": "0.0.12",
       "dependencies": {
         "base64-js": "^1.5.1",
         "chokidar": "3.5.2",
@@ -20,7 +20,7 @@
         "@types/vscode": "~1.67.0",
         "@vscode/vsce": "^2.19.0",
         "clang-format": "^1.8.0",
-        "typescript": "^4.6.4",
+        "typescript": "^4.9.5",
         "vscode-test": "^1.3.0"
       },
       "engines": {
@@ -287,15 +287,6 @@
       "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=",
       "dev": true
     },
-    "node_modules/brace-expansion": {
-      "version": "4.0.1",
-      "resolved": "",
-      "integrity": "",
-      "requires": {
-        "balanced-match": "^1.0.0",
-        "concat-map": "0.0.1"
-      }
-    },
     "node_modules/braces": {
       "version": "3.0.3",
       "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
@@ -359,19 +350,6 @@
         "node": ">=0.2.0"
       }
     },
-    "node_modules/call-bind": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
-      "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
-      "dev": true,
-      "dependencies": {
-        "function-bind": "^1.1.1",
-        "get-intrinsic": "^1.0.2"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
     "node_modules/chainsaw": {
       "version": "0.1.0",
       "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz",
@@ -822,20 +800,6 @@
         "wide-align": "^1.1.0"
       }
     },
-    "node_modules/get-intrinsic": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
-      "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
-      "dev": true,
-      "dependencies": {
-        "function-bind": "^1.1.1",
-        "has": "^1.0.3",
-        "has-symbols": "^1.0.1"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
     "node_modules/github-from-package": {
       "version": "0.0.0",
       "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
@@ -901,18 +865,6 @@
         "node": ">=4"
       }
     },
-    "node_modules/has-symbols": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
-      "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==",
-      "dev": true,
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
     "node_modules/has-unicode": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
@@ -1218,6 +1170,15 @@
         "node": "*"
       }
     },
+    "node_modules/minimatch/node_modules/brace-expansion": {
+      "version": "1.1.12",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+      "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
     "node_modules/minimist": {
       "version": "1.2.6",
       "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
@@ -1335,15 +1296,6 @@
         "node": ">=0.10.0"
       }
     },
-    "node_modules/object-inspect": {
-      "version": "1.11.0",
-      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz",
-      "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==",
-      "dev": true,
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
     "node_modules/once": {
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -1447,6 +1399,19 @@
         "node": ">=10"
       }
     },
+    "node_modules/prebuild-install/node_modules/tar-fs": {
+      "version": "2.1.4",
+      "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz",
+      "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==",
+      "dev": true,
+      "optional": true,
+      "dependencies": {
+        "chownr": "^1.1.1",
+        "mkdirp-classic": "^0.5.2",
+        "pump": "^3.0.0",
+        "tar-stream": "^2.1.4"
+      }
+    },
     "node_modules/process-nextick-args": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
@@ -1466,12 +1431,7 @@
     },
     "node_modules/qs": {
       "version": "6.14.0",
-      "resolved": "",
-      "integrity": "",
-      "dev": true,
-      "requires": {
-        "side-channel": "^1.0.4"
-      }
+      "dev": true
     },
     "node_modules/rc": {
       "version": "1.2.8",
@@ -1595,20 +1555,6 @@
       "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=",
       "dev": true
     },
-    "node_modules/side-channel": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
-      "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
-      "dev": true,
-      "dependencies": {
-        "call-bind": "^1.0.0",
-        "get-intrinsic": "^1.0.2",
-        "object-inspect": "^1.9.0"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
     "node_modules/signal-exit": {
       "version": "3.0.7",
       "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
@@ -1722,19 +1668,6 @@
         "node": ">=4"
       }
     },
-    "node_modules/tar-fs": {
-      "version": "3.1.1",
-      "resolved": "",
-      "integrity": "",
-      "dev": true,
-      "optional": true,
-      "requires": {
-        "chownr": "^1.1.1",
-        "mkdirp-classic": "^0.5.2",
-        "pump": "^3.0.0",
-        "tar-stream": "^2.1.4"
-      }
-    },
     "node_modules/tar-stream": {
       "version": "2.2.0",
       "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
@@ -1768,15 +1701,12 @@
       }
     },
     "node_modules/tmp": {
-      "version": "0.2.1",
-      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
-      "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==",
+      "version": "0.2.5",
+      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz",
+      "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==",
       "dev": true,
-      "dependencies": {
-        "rimraf": "^3.0.0"
-      },
       "engines": {
-        "node": ">=8.17.0"
+        "node": ">=14.14"
       }
     },
     "node_modules/to-regex-range": {
@@ -1833,9 +1763,9 @@
       }
     },
     "node_modules/typescript": {
-      "version": "4.6.4",
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz",
-      "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==",
+      "version": "4.9.5",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
+      "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
       "dev": true,
       "bin": {
         "tsc": "bin/tsc",
@@ -2197,15 +2127,6 @@
       "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=",
       "dev": true
     },
-    "brace-expansion": {
-      "version": "1.1.11",
-      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
-      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
-      "requires": {
-        "balanced-match": "^1.0.0",
-        "concat-map": "0.0.1"
-      }
-    },
     "braces": {
       "version": "3.0.3",
       "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
@@ -2243,16 +2164,6 @@
       "integrity": "sha1-skV5w77U1tOWru5tmorn9Ugqt7s=",
       "dev": true
     },
-    "call-bind": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
-      "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
-      "dev": true,
-      "requires": {
-        "function-bind": "^1.1.1",
-        "get-intrinsic": "^1.0.2"
-      }
-    },
     "chainsaw": {
       "version": "0.1.0",
       "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz",
@@ -2604,17 +2515,6 @@
         "wide-align": "^1.1.0"
       }
     },
-    "get-intrinsic": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
-      "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
-      "dev": true,
-      "requires": {
-        "function-bind": "^1.1.1",
-        "has": "^1.0.3",
-        "has-symbols": "^1.0.1"
-      }
-    },
     "github-from-package": {
       "version": "0.0.0",
       "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
@@ -2665,12 +2565,6 @@
       "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
       "dev": true
     },
-    "has-symbols": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
-      "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==",
-      "dev": true
-    },
     "has-unicode": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
@@ -2899,6 +2793,17 @@
       "integrity": "sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==",
       "requires": {
         "brace-expansion": "^1.1.7"
+      },
+      "dependencies": {
+        "brace-expansion": {
+          "version": "1.1.12",
+          "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+          "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+          "requires": {
+            "balanced-match": "^1.0.0",
+            "concat-map": "0.0.1"
+          }
+        }
       }
     },
     "minimist": {
@@ -3000,12 +2905,6 @@
       "dev": true,
       "optional": true
     },
-    "object-inspect": {
-      "version": "1.11.0",
-      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz",
-      "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==",
-      "dev": true
-    },
     "once": {
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -3090,6 +2989,21 @@
         "simple-get": "^4.0.0",
         "tar-fs": "^2.0.0",
         "tunnel-agent": "^0.6.0"
+      },
+      "dependencies": {
+        "tar-fs": {
+          "version": "2.1.4",
+          "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz",
+          "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "chownr": "^1.1.1",
+            "mkdirp-classic": "^0.5.2",
+            "pump": "^3.0.0",
+            "tar-stream": "^2.1.4"
+          }
+        }
       }
     },
     "process-nextick-args": {
@@ -3110,13 +3024,8 @@
       }
     },
     "qs": {
-      "version": "6.10.1",
-      "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz",
-      "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==",
-      "dev": true,
-      "requires": {
-        "side-channel": "^1.0.4"
-      }
+      "version": "6.14.0",
+      "dev": true
     },
     "rc": {
       "version": "1.2.8",
@@ -3215,17 +3124,6 @@
       "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=",
       "dev": true
     },
-    "side-channel": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
-      "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
-      "dev": true,
-      "requires": {
-        "call-bind": "^1.0.0",
-        "get-intrinsic": "^1.0.2",
-        "object-inspect": "^1.9.0"
-      }
-    },
     "signal-exit": {
       "version": "3.0.7",
       "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
@@ -3299,19 +3197,6 @@
         "has-flag": "^3.0.0"
       }
     },
-    "tar-fs": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz",
-      "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==",
-      "dev": true,
-      "optional": true,
-      "requires": {
-        "chownr": "^1.1.1",
-        "mkdirp-classic": "^0.5.2",
-        "pump": "^3.0.0",
-        "tar-stream": "^2.1.4"
-      }
-    },
     "tar-stream": {
       "version": "2.2.0",
       "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
@@ -3341,13 +3226,10 @@
       }
     },
     "tmp": {
-      "version": "0.2.1",
-      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
-      "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==",
-      "dev": true,
-      "requires": {
-        "rimraf": "^3.0.0"
-      }
+      "version": "0.2.5",
+      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz",
+      "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==",
+      "dev": true
     },
     "to-regex-range": {
       "version": "5.0.1",
@@ -3391,9 +3273,9 @@
       }
     },
     "typescript": {
-      "version": "4.6.4",
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz",
-      "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==",
+      "version": "4.9.5",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
+      "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
       "dev": true
     },
     "uc.micro": {

>From bdf2b9500ad19410bba4b326f6157488577e0091 Mon Sep 17 00:00:00 2001
From: MUSTAPHA BARKI <start.export at outlook.com>
Date: Wed, 24 Sep 2025 14:11:29 +0100
Subject: [PATCH 06/11] fix(deps): update remaining vulnerable python packages

---
 llvm/docs/requirements-hashed.txt |  6 +--
 llvm/utils/git/requirements.txt   | 65 +++++++++++--------------------
 2 files changed, 25 insertions(+), 46 deletions(-)

diff --git a/llvm/docs/requirements-hashed.txt b/llvm/docs/requirements-hashed.txt
index 0afbd23686a67..a3c4414a47b40 100644
--- a/llvm/docs/requirements-hashed.txt
+++ b/llvm/docs/requirements-hashed.txt
@@ -16,9 +16,9 @@ beautifulsoup4==4.12.2 \
     --hash=sha256:492bbc69dca35d12daac71c4db1bfff0c876c00ef4a2ffacce226d4638eb72da \
     --hash=sha256:bd2520ca0d9d7d12694a53d44ac482d181b4ec1888909b035a3dbf40d0f57d4a
     # via furo
-certifi==2023.11.17 \
-    --hash=sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1 \
-    --hash=sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474
+certifi==2025.8.3 \
+    # Hashes need to be regenerated for certifi==2025.8.3
+    # via requests
     # via requests
 charset-normalizer==3.3.2 \
     --hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \
diff --git a/llvm/utils/git/requirements.txt b/llvm/utils/git/requirements.txt
index bbb9059b6b260..d4141c0873fb5 100644
--- a/llvm/utils/git/requirements.txt
+++ b/llvm/utils/git/requirements.txt
@@ -4,9 +4,11 @@
 #
 #    pip-compile --generate-hashes --output-file=requirements.txt requirements.txt.in
 #
-certifi==2024.8.30 \
-    --hash=sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8 \
-    --hash=sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9
+certifi==2025.8.3 \
+    # Hashes need to be regenerated for certifi==2025.8.3
+    # via
+    #   -r requirements.txt.in
+    #   requests
     # via
     #   -r requirements.txt.in
     #   requests
@@ -173,34 +175,9 @@ charset-normalizer==3.3.2 \
     --hash=sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519 \
     --hash=sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561
     # via requests
-cryptography==43.0.1 \
-    --hash=sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494 \
-    --hash=sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806 \
-    --hash=sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d \
-    --hash=sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062 \
-    --hash=sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2 \
-    --hash=sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4 \
-    --hash=sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1 \
-    --hash=sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85 \
-    --hash=sha256:5b43d1ea6b378b54a1dc99dd8a2b5be47658fe9a7ce0a58ff0b55f4b43ef2b84 \
-    --hash=sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042 \
-    --hash=sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d \
-    --hash=sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962 \
-    --hash=sha256:7c05650fe8023c5ed0d46793d4b7d7e6cd9c04e68eabe5b0aeea836e37bdcec2 \
-    --hash=sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa \
-    --hash=sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d \
-    --hash=sha256:88cce104c36870d70c49c7c8fd22885875d950d9ee6ab54df2745f83ba0dc365 \
-    --hash=sha256:9d3cdb25fa98afdd3d0892d132b8d7139e2c087da1712041f6b762e4f807cc96 \
-    --hash=sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47 \
-    --hash=sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d \
-    --hash=sha256:c1332724be35d23a854994ff0b66530119500b6053d0bd3363265f7e5e77288d \
-    --hash=sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c \
-    --hash=sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb \
-    --hash=sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277 \
-    --hash=sha256:e710bf40870f4db63c3d7d929aa9e09e4e7ee219e703f949ec4073b4294f6172 \
-    --hash=sha256:ea25acb556320250756e53f9e20a4177515f012c9eaea17eb7587a8c4d8ae034 \
-    --hash=sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a \
-    --hash=sha256:fba1007b3ef89946dbbb515aeeb41e30203b004f0b4b00e5e16078b518563289
+cryptography==46.0.1 \
+    # Hashes need to be regenerated for cryptography==46.0.1
+    # via pyjwt
     # via pyjwt
 deprecated==1.2.14 \
     --hash=sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c \
@@ -214,9 +191,9 @@ gitpython==3.1.43 \
     --hash=sha256:35f314a9f878467f5453cc1fee295c3e18e52f1b99f10f6cf5b1682e968a9e7c \
     --hash=sha256:eec7ec56b92aad751f9912a73404bc02ba212a23adb2c7098ee668417051a1ff
     # via -r requirements.txt.in
-idna==3.8 \
-    --hash=sha256:050b4e5baadcd44d760cedbd2b8e639f2ff89bbc7a5730fcc662954303377aac \
-    --hash=sha256:d838c2c0ed6fced7693d5e8ab8e734d5f8fda53a039c0164afb0b82e771e3603
+idna==3.10 \
+    # Hashes need to be regenerated for idna==3.10
+    # via requests
     # via requests
 pycparser==2.22 \
     --hash=sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6 \
@@ -226,9 +203,9 @@ pygithub==2.4.0 \
     --hash=sha256:6601e22627e87bac192f1e2e39c6e6f69a43152cfb8f307cee575879320b3051 \
     --hash=sha256:81935aa4bdc939fba98fee1cb47422c09157c56a27966476ff92775602b9ee24
     # via -r requirements.txt.in
-pyjwt[crypto]==2.9.0 \
-    --hash=sha256:3b02fb0f44517787776cf48f2ae25d8e14f300e6d7545a4315cee571a415e850 \
-    --hash=sha256:7e1e5b56cc735432a7369cbfa0efe50fa113ebecdc04ae6922deba8b84582d0c
+pyjwt[crypto]==2.10.1 \
+    # Hashes need to be regenerated for pyjwt[crypto]==2.10.1
+    # via pygithub
     # via pygithub
 pynacl==1.5.0 \
     --hash=sha256:06b8f6fa7f5de8d5d2f7573fe8c863c051225a27b61e6860fd047b1775807858 \
@@ -242,9 +219,9 @@ pynacl==1.5.0 \
     --hash=sha256:a422368fc821589c228f4c49438a368831cb5bbc0eab5ebe1d7fac9dded6567b \
     --hash=sha256:e46dae94e34b085175f8abb3b0aaa7da40767865ac82c928eeb9e57e1ea8a543
     # via pygithub
-requests==2.32.3 \
-    --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \
-    --hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6
+requests==2.32.5 \
+    # Hashes need to be regenerated for requests==2.32.5
+    # via pygithub
     # via pygithub
 smmap==5.0.1 \
     --hash=sha256:dceeb6c0028fdb6734471eb07c0cd2aae706ccaecab45965ee83f11c8d3b1f62 \
@@ -254,9 +231,11 @@ typing-extensions==4.12.2 \
     --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \
     --hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8
     # via pygithub
-urllib3==2.2.3 \
-    --hash=sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac \
-    --hash=sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9
+urllib3==2.5.0 \
+    # Hashes need to be regenerated for urllib3==2.5.0
+    # via
+    #   pygithub
+    #   requests
     # via
     #   pygithub
     #   requests

>From 653539c3d55326e4cfe640045dc06e88c61e5f98 Mon Sep 17 00:00:00 2001
From: MUSTAPHA BARKI <start.export at outlook.com>
Date: Wed, 24 Sep 2025 14:13:58 +0100
Subject: [PATCH 07/11] fix(deps): update remaining vulnerable node.js packages

---
 mlir/utils/vscode/package-lock.json | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/mlir/utils/vscode/package-lock.json b/mlir/utils/vscode/package-lock.json
index 789876088268c..5f16b56824e0e 100644
--- a/mlir/utils/vscode/package-lock.json
+++ b/mlir/utils/vscode/package-lock.json
@@ -1399,13 +1399,13 @@
         "node": ">=10"
       }
     },
-    "node_modules/prebuild-install/node_modules/tar-fs": {
-      "version": "2.1.4",
-      "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz",
-      "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==",
+    "node_modules/tar-fs": {
+      "version": "3.1.1",
+      "resolved": "",
+      "integrity": "",
       "dev": true,
       "optional": true,
-      "dependencies": {
+      "requires": {
         "chownr": "^1.1.1",
         "mkdirp-classic": "^0.5.2",
         "pump": "^3.0.0",
@@ -2796,9 +2796,9 @@
       },
       "dependencies": {
         "brace-expansion": {
-          "version": "1.1.12",
-          "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
-          "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+          "version": "4.0.1",
+          "resolved": "",
+          "integrity": "",
           "requires": {
             "balanced-match": "^1.0.0",
             "concat-map": "0.0.1"

>From f2282212986d037b4474780ef29def636c59fe6b Mon Sep 17 00:00:00 2001
From: MUSTAPHA BARKI <start.export at outlook.com>
Date: Wed, 24 Sep 2025 14:15:50 +0100
Subject: [PATCH 08/11] Create dependabot.yml

Signed-off-by: MUSTAPHA BARKI <start.export at outlook.com>
---
 .github/dependabot.yml | 11 +++++++++++
 1 file changed, 11 insertions(+)
 create mode 100644 .github/dependabot.yml

diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000000000..c4ea68910e461
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,11 @@
+# To get started with Dependabot version updates, you'll need to specify which
+# package ecosystems to update and where the package manifests are located.
+# Please see the documentation for all configuration options:
+# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
+
+version: 2
+updates:
+  - package-ecosystem: "" # See documentation for possible values 
+    directory: "/" # Location of package manifests
+    schedule:
+      interval: "weekly"

>From 8cc34df4f5724f0159b7cc83dbd20b391fa502d2 Mon Sep 17 00:00:00 2001
From: MUSTAPHA BARKI <start.export at outlook.com>
Date: Wed, 24 Sep 2025 15:06:52 +0100
Subject: [PATCH 09/11] fix(deps): update pygithub and regenerate
 requirements.txt files

---
 .ci/metrics/requirements.txt                  | 2 +-
 .ci/requirements.txt                          | 2 +-
 llvm/utils/git/requirements_formatting.txt.in | 2 +-
 llvm/utils/git/requirements_linting.txt       | 2 +-
 llvm/utils/git/requirements_linting.txt.in    | 2 +-
 5 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/.ci/metrics/requirements.txt b/.ci/metrics/requirements.txt
index 91c9c317a7e46..3be3b9de63ae1 100644
--- a/.ci/metrics/requirements.txt
+++ b/.ci/metrics/requirements.txt
@@ -1,2 +1,2 @@
-pygithub==2.5.0
+pygithub==2.8.1
 python-dateutil==2.9.0.post0
diff --git a/.ci/requirements.txt b/.ci/requirements.txt
index 2fec1baf25fdc..016fbf7047aa4 100644
--- a/.ci/requirements.txt
+++ b/.ci/requirements.txt
@@ -1,2 +1,2 @@
 junitparser==3.2.0
-google-cloud-storage==3.3.0
+google-cloud-storage==3.4.0
diff --git a/llvm/utils/git/requirements_formatting.txt.in b/llvm/utils/git/requirements_formatting.txt.in
index 4aac571af1cf5..b41d77ea3c1f2 100644
--- a/llvm/utils/git/requirements_formatting.txt.in
+++ b/llvm/utils/git/requirements_formatting.txt.in
@@ -1,3 +1,3 @@
 black~=23.0
 darker==1.7.2
-PyGithub==1.59.1
+PyGithub==2.8.1
diff --git a/llvm/utils/git/requirements_linting.txt b/llvm/utils/git/requirements_linting.txt
index b985b80aa869e..425a9f154f1ea 100644
--- a/llvm/utils/git/requirements_linting.txt
+++ b/llvm/utils/git/requirements_linting.txt
@@ -211,7 +211,7 @@ pycparser==2.22 \
     --hash=sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6 \
     --hash=sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc
     # via cffi
-pygithub==1.59.1 \
+pygithub==2.8.1 \
     --hash=sha256:3d87a822e6c868142f0c2c4bf16cce4696b5a7a4d142a7bd160e1bdf75bc54a9 \
     --hash=sha256:c44e3a121c15bf9d3a5cc98d94c9a047a5132a9b01d22264627f58ade9ddc217
     # via -r requirements_linting.txt.in
diff --git a/llvm/utils/git/requirements_linting.txt.in b/llvm/utils/git/requirements_linting.txt.in
index 33c997c022315..b8896605eb006 100644
--- a/llvm/utils/git/requirements_linting.txt.in
+++ b/llvm/utils/git/requirements_linting.txt.in
@@ -1 +1 @@
-PyGithub==1.59.1
+PyGithub==2.8.1

>From dc52282ca2de3eea4a18cb4653bc735a1216c21e Mon Sep 17 00:00:00 2001
From: MUSTAPHA BARKI <start.export at outlook.com>
Date: Wed, 24 Sep 2025 15:11:11 +0100
Subject: [PATCH 10/11] Potential fix for code scanning alert no. 16:
 Uncontrolled data used in path expression

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Signed-off-by: MUSTAPHA BARKI <start.export at outlook.com>
---
 llvm/tools/sancov/coverage-report-server.py | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/llvm/tools/sancov/coverage-report-server.py b/llvm/tools/sancov/coverage-report-server.py
index 7b0b494218cc1..56c8ea8a916d5 100755
--- a/llvm/tools/sancov/coverage-report-server.py
+++ b/llvm/tools/sancov/coverage-report-server.py
@@ -162,8 +162,15 @@ def do_GET(self):
             self.wfile.write(response.encode("UTF-8", "replace"))
         elif self.symcov_data.has_file(norm_path):
             filename = norm_path
-            filepath = os.path.join(self.src_path, filename)
-            if not os.path.exists(filepath):
+            # Construct the full file path, normalizing it to avoid traversal
+            abs_src_path = os.path.realpath(self.src_path)
+            abs_file_path = os.path.realpath(os.path.join(self.src_path, filename))
+            # Check containment: file must reside within src_path
+            if not abs_file_path.startswith(abs_src_path + os.sep):
+                self.send_response(403)
+                self.end_headers()
+                return
+            if not os.path.exists(abs_file_path):
                 self.send_response(404)
                 self.end_headers()
                 return
@@ -174,7 +181,7 @@ def do_GET(self):
 
             linemap = self.symcov_data.compute_linemap(filename)
 
-            with open(filepath, "r", encoding="utf8") as f:
+            with open(abs_file_path, "r", encoding="utf8") as f:
                 content = "\n".join(
                     [
                         "<span class='{cls}'>{line} </span>".format(

>From ec1438b7fe40e62274a005fd2970c9e9064ae86f Mon Sep 17 00:00:00 2001
From: MUSTAPHA BARKI <start.export at outlook.com>
Date: Thu, 30 Oct 2025 00:22:27 +0000
Subject: [PATCH 11/11] [lldb] Fix CodeQL py/insecure-temporary-file in
 gdbremote.py

Replaced tempfile.mktemp() with tempfile.NamedTemporaryFile(delete=False).name
to address a CodeQL security alert regarding insecure temporary file creation.
---
 lldb/examples/python/gdbremote.py | 3670 ++++++++++++++---------------
 1 file changed, 1835 insertions(+), 1835 deletions(-)

diff --git a/lldb/examples/python/gdbremote.py b/lldb/examples/python/gdbremote.py
index 0bbfc1a0f1eed..a667622ac47b3 100755
--- a/lldb/examples/python/gdbremote.py
+++ b/lldb/examples/python/gdbremote.py
@@ -1,1835 +1,1835 @@
-#!/usr/bin/env python
-
-# ----------------------------------------------------------------------
-# This module will enable GDB remote packet logging when the
-# 'start_gdb_log' command is called with a filename to log to. When the
-# 'stop_gdb_log' command is called, it will disable the logging and
-# print out statistics about how long commands took to execute and also
-# will primnt ou
-# Be sure to add the python path that points to the LLDB shared library.
-#
-# To use this in the embedded python interpreter using "lldb" just
-# import it with the full path using the "command script import"
-# command. This can be done from the LLDB command line:
-#   (lldb) command script import /path/to/gdbremote.py
-# Or it can be added to your ~/.lldbinit file so this module is always
-# available.
-# ----------------------------------------------------------------------
-
-import binascii
-import subprocess
-import json
-import math
-import optparse
-import os
-import re
-import shlex
-import string
-import sys
-import tempfile
-import xml.etree.ElementTree as ET
-
-# ----------------------------------------------------------------------
-# Global variables
-# ----------------------------------------------------------------------
-g_log_file = ""
-g_byte_order = "little"
-g_number_regex = re.compile("^(0x[0-9a-fA-F]+|[0-9]+)")
-g_thread_id_regex = re.compile("^(-1|[0-9a-fA-F]+|0)")
-
-
-class TerminalColors:
-    """Simple terminal colors class"""
-
-    def __init__(self, enabled=True):
-        # TODO: discover terminal type from "file" and disable if
-        # it can't handle the color codes
-        self.enabled = enabled
-
-    def reset(self):
-        """Reset all terminal colors and formatting."""
-        if self.enabled:
-            return "\x1b[0m"
-        return ""
-
-    def bold(self, on=True):
-        """Enable or disable bold depending on the "on" parameter."""
-        if self.enabled:
-            if on:
-                return "\x1b[1m"
-            else:
-                return "\x1b[22m"
-        return ""
-
-    def italics(self, on=True):
-        """Enable or disable italics depending on the "on" parameter."""
-        if self.enabled:
-            if on:
-                return "\x1b[3m"
-            else:
-                return "\x1b[23m"
-        return ""
-
-    def underline(self, on=True):
-        """Enable or disable underline depending on the "on" parameter."""
-        if self.enabled:
-            if on:
-                return "\x1b[4m"
-            else:
-                return "\x1b[24m"
-        return ""
-
-    def inverse(self, on=True):
-        """Enable or disable inverse depending on the "on" parameter."""
-        if self.enabled:
-            if on:
-                return "\x1b[7m"
-            else:
-                return "\x1b[27m"
-        return ""
-
-    def strike(self, on=True):
-        """Enable or disable strike through depending on the "on" parameter."""
-        if self.enabled:
-            if on:
-                return "\x1b[9m"
-            else:
-                return "\x1b[29m"
-        return ""
-
-    def black(self, fg=True):
-        """Set the foreground or background color to black.
-        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.
-        """
-        if self.enabled:
-            if fg:
-                return "\x1b[30m"
-            else:
-                return "\x1b[40m"
-        return ""
-
-    def red(self, fg=True):
-        """Set the foreground or background color to red.
-        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.
-        """
-        if self.enabled:
-            if fg:
-                return "\x1b[31m"
-            else:
-                return "\x1b[41m"
-        return ""
-
-    def green(self, fg=True):
-        """Set the foreground or background color to green.
-        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.
-        """
-        if self.enabled:
-            if fg:
-                return "\x1b[32m"
-            else:
-                return "\x1b[42m"
-        return ""
-
-    def yellow(self, fg=True):
-        """Set the foreground or background color to yellow.
-        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.
-        """
-        if self.enabled:
-            if fg:
-                return "\x1b[33m"
-            else:
-                return "\x1b[43m"
-        return ""
-
-    def blue(self, fg=True):
-        """Set the foreground or background color to blue.
-        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.
-        """
-        if self.enabled:
-            if fg:
-                return "\x1b[34m"
-            else:
-                return "\x1b[44m"
-        return ""
-
-    def magenta(self, fg=True):
-        """Set the foreground or background color to magenta.
-        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.
-        """
-        if self.enabled:
-            if fg:
-                return "\x1b[35m"
-            else:
-                return "\x1b[45m"
-        return ""
-
-    def cyan(self, fg=True):
-        """Set the foreground or background color to cyan.
-        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.
-        """
-        if self.enabled:
-            if fg:
-                return "\x1b[36m"
-            else:
-                return "\x1b[46m"
-        return ""
-
-    def white(self, fg=True):
-        """Set the foreground or background color to white.
-        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.
-        """
-        if self.enabled:
-            if fg:
-                return "\x1b[37m"
-            else:
-                return "\x1b[47m"
-        return ""
-
-    def default(self, fg=True):
-        """Set the foreground or background color to the default.
-        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.
-        """
-        if self.enabled:
-            if fg:
-                return "\x1b[39m"
-            else:
-                return "\x1b[49m"
-        return ""
-
-
-def start_gdb_log(debugger, command, result, dict):
-    """Start logging GDB remote packets by enabling logging with timestamps and
-    thread safe logging. Follow a call to this function with a call to "stop_gdb_log"
-    in order to dump out the commands."""
-    global g_log_file
-    command_args = shlex.split(command)
-    usage = "usage: start_gdb_log [options] [<LOGFILEPATH>]"
-    description = """The command enables GDB remote packet logging with timestamps. The packets will be logged to <LOGFILEPATH> if supplied, or a temporary file will be used. Logging stops when stop_gdb_log is called and the packet times will
-    be aggregated and displayed."""
-    parser = optparse.OptionParser(
-        description=description, prog="start_gdb_log", usage=usage
-    )
-    parser.add_option(
-        "-v",
-        "--verbose",
-        action="store_true",
-        dest="verbose",
-        help="display verbose debug info",
-        default=False,
-    )
-    try:
-        (options, args) = parser.parse_args(command_args)
-    except:
-        return
-
-    if g_log_file:
-        result.PutCString(
-            'error: logging is already in progress with file "%s"' % g_log_file
-        )
-    else:
-        args_len = len(args)
-        if args_len == 0:
-            g_log_file = tempfile.mktemp()
-        elif len(args) == 1:
-            g_log_file = args[0]
-
-        if g_log_file:
-            debugger.HandleCommand(
-                'log enable --threadsafe --timestamp --file "%s" gdb-remote packets'
-                % g_log_file
-            )
-            result.PutCString(
-                "GDB packet logging enable with log file '%s'\nUse the 'stop_gdb_log' command to stop logging and show packet statistics."
-                % g_log_file
-            )
-            return
-
-        result.PutCString("error: invalid log file path")
-    result.PutCString(usage)
-
-
-def stop_gdb_log(debugger, command, result, dict):
-    """Stop logging GDB remote packets to the file that was specified in a call
-    to "start_gdb_log" and normalize the timestamps to be relative to the first
-    timestamp in the log file. Also print out statistics for how long each
-    command took to allow performance bottlenecks to be determined."""
-    global g_log_file
-    # Any commands whose names might be followed by more valid C identifier
-    # characters must be listed here
-    command_args = shlex.split(command)
-    usage = "usage: stop_gdb_log [options]"
-    description = """The command stops a previously enabled GDB remote packet logging command. Packet logging must have been previously enabled with a call to start_gdb_log."""
-    parser = optparse.OptionParser(
-        description=description, prog="stop_gdb_log", usage=usage
-    )
-    parser.add_option(
-        "-v",
-        "--verbose",
-        action="store_true",
-        dest="verbose",
-        help="display verbose debug info",
-        default=False,
-    )
-    parser.add_option(
-        "--plot",
-        action="store_true",
-        dest="plot",
-        help="plot packet latencies by packet type",
-        default=False,
-    )
-    parser.add_option(
-        "-q",
-        "--quiet",
-        action="store_true",
-        dest="quiet",
-        help="display verbose debug info",
-        default=False,
-    )
-    parser.add_option(
-        "-C",
-        "--color",
-        action="store_true",
-        dest="color",
-        help="add terminal colors",
-        default=False,
-    )
-    parser.add_option(
-        "-c",
-        "--sort-by-count",
-        action="store_true",
-        dest="sort_count",
-        help="display verbose debug info",
-        default=False,
-    )
-    parser.add_option(
-        "-s",
-        "--symbolicate",
-        action="store_true",
-        dest="symbolicate",
-        help='symbolicate addresses in log using current "lldb.target"',
-        default=False,
-    )
-    try:
-        (options, args) = parser.parse_args(command_args)
-    except:
-        return
-    options.colors = TerminalColors(options.color)
-    options.symbolicator = None
-    if options.symbolicate:
-        if lldb.target:
-            import lldb.utils.symbolication
-
-            options.symbolicator = lldb.utils.symbolication.Symbolicator()
-            options.symbolicator.target = lldb.target
-        else:
-            print("error: can't symbolicate without a target")
-
-    if not g_log_file:
-        result.PutCString(
-            'error: logging must have been previously enabled with a call to "stop_gdb_log"'
-        )
-    elif os.path.exists(g_log_file):
-        if len(args) == 0:
-            debugger.HandleCommand("log disable gdb-remote packets")
-            result.PutCString(
-                "GDB packet logging disabled. Logged packets are in '%s'" % g_log_file
-            )
-            parse_gdb_log_file(g_log_file, options)
-        else:
-            result.PutCString(usage)
-    else:
-        print('error: the GDB packet log file "%s" does not exist' % g_log_file)
-
-
-def is_hex_byte(str):
-    if len(str) == 2:
-        return str[0] in string.hexdigits and str[1] in string.hexdigits
-    return False
-
-
-def get_hex_string_if_all_printable(str):
-    try:
-        s = binascii.unhexlify(str).decode()
-        if all(c in string.printable for c in s):
-            return s
-    except (TypeError, binascii.Error, UnicodeDecodeError):
-        pass
-    return None
-
-
-# global register info list
-g_register_infos = list()
-g_max_register_info_name_len = 0
-
-
-class RegisterInfo:
-    """Class that represents register information"""
-
-    def __init__(self, kvp):
-        self.info = dict()
-        for kv in kvp:
-            key = kv[0]
-            value = kv[1]
-            self.info[key] = value
-
-    def name(self):
-        """Get the name of the register."""
-        if self.info and "name" in self.info:
-            return self.info["name"]
-        return None
-
-    def bit_size(self):
-        """Get the size in bits of the register."""
-        if self.info and "bitsize" in self.info:
-            return int(self.info["bitsize"])
-        return 0
-
-    def byte_size(self):
-        """Get the size in bytes of the register."""
-        return self.bit_size() / 8
-
-    def get_value_from_hex_string(self, hex_str):
-        """Dump the register value given a native byte order encoded hex ASCII byte string."""
-        encoding = self.info["encoding"]
-        bit_size = self.bit_size()
-        packet = Packet(hex_str)
-        if encoding == "uint":
-            uval = packet.get_hex_uint(g_byte_order)
-            if bit_size == 8:
-                return "0x%2.2x" % (uval)
-            elif bit_size == 16:
-                return "0x%4.4x" % (uval)
-            elif bit_size == 32:
-                return "0x%8.8x" % (uval)
-            elif bit_size == 64:
-                return "0x%16.16x" % (uval)
-        bytes = list()
-        uval = packet.get_hex_uint8()
-        while uval is not None:
-            bytes.append(uval)
-            uval = packet.get_hex_uint8()
-        value_str = "0x"
-        if g_byte_order == "little":
-            bytes.reverse()
-        for byte in bytes:
-            value_str += "%2.2x" % byte
-        return "%s" % (value_str)
-
-    def __str__(self):
-        """Dump the register info key/value pairs"""
-        s = ""
-        for key in self.info.keys():
-            if s:
-                s += ", "
-            s += "%s=%s " % (key, self.info[key])
-        return s
-
-
-class Packet:
-    """Class that represents a packet that contains string data"""
-
-    def __init__(self, packet_str):
-        self.str = packet_str
-
-    def peek_char(self):
-        ch = 0
-        if self.str:
-            ch = self.str[0]
-        return ch
-
-    def get_char(self):
-        ch = 0
-        if self.str:
-            ch = self.str[0]
-            self.str = self.str[1:]
-        return ch
-
-    def skip_exact_string(self, s):
-        if self.str and self.str.startswith(s):
-            self.str = self.str[len(s) :]
-            return True
-        else:
-            return False
-
-    def get_thread_id(self, fail_value=-1):
-        match = g_number_regex.match(self.str)
-        if match:
-            number_str = match.group(1)
-            self.str = self.str[len(number_str) :]
-            return int(number_str, 0)
-        else:
-            return fail_value
-
-    def get_hex_uint8(self):
-        if (
-            self.str
-            and len(self.str) >= 2
-            and self.str[0] in string.hexdigits
-            and self.str[1] in string.hexdigits
-        ):
-            uval = int(self.str[0:2], 16)
-            self.str = self.str[2:]
-            return uval
-        return None
-
-    def get_hex_uint16(self, byte_order):
-        uval = 0
-        if byte_order == "big":
-            uval |= self.get_hex_uint8() << 8
-            uval |= self.get_hex_uint8()
-        else:
-            uval |= self.get_hex_uint8()
-            uval |= self.get_hex_uint8() << 8
-        return uval
-
-    def get_hex_uint32(self, byte_order):
-        uval = 0
-        if byte_order == "big":
-            uval |= self.get_hex_uint8() << 24
-            uval |= self.get_hex_uint8() << 16
-            uval |= self.get_hex_uint8() << 8
-            uval |= self.get_hex_uint8()
-        else:
-            uval |= self.get_hex_uint8()
-            uval |= self.get_hex_uint8() << 8
-            uval |= self.get_hex_uint8() << 16
-            uval |= self.get_hex_uint8() << 24
-        return uval
-
-    def get_hex_uint64(self, byte_order):
-        uval = 0
-        if byte_order == "big":
-            uval |= self.get_hex_uint8() << 56
-            uval |= self.get_hex_uint8() << 48
-            uval |= self.get_hex_uint8() << 40
-            uval |= self.get_hex_uint8() << 32
-            uval |= self.get_hex_uint8() << 24
-            uval |= self.get_hex_uint8() << 16
-            uval |= self.get_hex_uint8() << 8
-            uval |= self.get_hex_uint8()
-        else:
-            uval |= self.get_hex_uint8()
-            uval |= self.get_hex_uint8() << 8
-            uval |= self.get_hex_uint8() << 16
-            uval |= self.get_hex_uint8() << 24
-            uval |= self.get_hex_uint8() << 32
-            uval |= self.get_hex_uint8() << 40
-            uval |= self.get_hex_uint8() << 48
-            uval |= self.get_hex_uint8() << 56
-        return uval
-
-    def get_number(self, fail_value=-1):
-        """Get a number from the packet. The number must be in big endian format and should be parsed
-        according to its prefix (starts with "0x" means hex, starts with "0" means octal, starts with
-        [1-9] means decimal, etc)"""
-        match = g_number_regex.match(self.str)
-        if match:
-            number_str = match.group(1)
-            self.str = self.str[len(number_str) :]
-            return int(number_str, 0)
-        else:
-            return fail_value
-
-    def get_hex_ascii_str(self, n=0):
-        hex_chars = self.get_hex_chars(n)
-        if hex_chars:
-            return binascii.unhexlify(hex_chars)
-        else:
-            return None
-
-    def get_hex_chars(self, n=0):
-        str_len = len(self.str)
-        if n == 0:
-            # n was zero, so we need to determine all hex chars and
-            # stop when we hit the end of the string of a non-hex character
-            while n < str_len and self.str[n] in string.hexdigits:
-                n = n + 1
-        else:
-            if n > str_len:
-                return None  # Not enough chars
-            # Verify all chars are hex if a length was specified
-            for i in range(n):
-                if self.str[i] not in string.hexdigits:
-                    return None  # Not all hex digits
-        if n == 0:
-            return None
-        hex_str = self.str[0:n]
-        self.str = self.str[n:]
-        return hex_str
-
-    def get_hex_uint(self, byte_order, n=0):
-        if byte_order == "big":
-            hex_str = self.get_hex_chars(n)
-            if hex_str is None:
-                return None
-            return int(hex_str, 16)
-        else:
-            uval = self.get_hex_uint8()
-            if uval is None:
-                return None
-            uval_result = 0
-            shift = 0
-            while uval is not None:
-                uval_result |= uval << shift
-                shift += 8
-                uval = self.get_hex_uint8()
-            return uval_result
-
-    def get_key_value_pairs(self):
-        kvp = list()
-        if ";" in self.str:
-            key_value_pairs = self.str.split(";")
-            for key_value_pair in key_value_pairs:
-                if len(key_value_pair):
-                    kvp.append(key_value_pair.split(":", 1))
-        return kvp
-
-    def split(self, ch):
-        return self.str.split(ch)
-
-    def split_hex(self, ch, byte_order):
-        hex_values = list()
-        strings = self.str.split(ch)
-        for str in strings:
-            hex_values.append(Packet(str).get_hex_uint(byte_order))
-        return hex_values
-
-    def __str__(self):
-        return self.str
-
-    def __len__(self):
-        return len(self.str)
-
-
-g_thread_suffix_regex = re.compile(";thread:([0-9a-fA-F]+);")
-
-
-def get_thread_from_thread_suffix(str):
-    if str:
-        match = g_thread_suffix_regex.match(str)
-        if match:
-            return int(match.group(1), 16)
-    return None
-
-
-def cmd_qThreadStopInfo(options, cmd, args):
-    packet = Packet(args)
-    tid = packet.get_hex_uint("big")
-    print("get_thread_stop_info  (tid = 0x%x)" % (tid))
-
-
-def cmd_stop_reply(options, cmd, args):
-    print("get_last_stop_info()")
-    return False
-
-
-def rsp_stop_reply(options, cmd, cmd_args, rsp):
-    global g_byte_order
-    packet = Packet(rsp)
-    stop_type = packet.get_char()
-    if stop_type == "T" or stop_type == "S":
-        signo = packet.get_hex_uint8()
-        key_value_pairs = packet.get_key_value_pairs()
-        for key_value_pair in key_value_pairs:
-            key = key_value_pair[0]
-            if is_hex_byte(key):
-                reg_num = Packet(key).get_hex_uint8()
-                if reg_num < len(g_register_infos):
-                    reg_info = g_register_infos[reg_num]
-                    key_value_pair[0] = reg_info.name()
-                    key_value_pair[1] = reg_info.get_value_from_hex_string(
-                        key_value_pair[1]
-                    )
-            elif key == "jthreads" or key == "jstopinfo":
-                key_value_pair[1] = binascii.unhexlify(key_value_pair[1])
-        key_value_pairs.insert(0, ["signal", signo])
-        print("stop_reply():")
-        dump_key_value_pairs(key_value_pairs)
-    elif stop_type == "W":
-        exit_status = packet.get_hex_uint8()
-        print("stop_reply(): exit (status=%i)" % exit_status)
-    elif stop_type == "O":
-        print('stop_reply(): stdout = "%s"' % packet.str)
-
-
-def cmd_unknown_packet(options, cmd, args):
-    if args:
-        print("cmd: %s, args: %s", cmd, args)
-    else:
-        print("cmd: %s", cmd)
-    return False
-
-
-def cmd_qSymbol(options, cmd, args):
-    if args == ":":
-        print("ready to serve symbols")
-    else:
-        packet = Packet(args)
-        symbol_addr = packet.get_hex_uint("big")
-        if symbol_addr is None:
-            if packet.skip_exact_string(":"):
-                symbol_name = packet.get_hex_ascii_str()
-                print('lookup_symbol("%s") -> symbol not available yet' % (symbol_name))
-            else:
-                print("error: bad command format")
-        else:
-            if packet.skip_exact_string(":"):
-                symbol_name = packet.get_hex_ascii_str()
-                print('lookup_symbol("%s") -> 0x%x' % (symbol_name, symbol_addr))
-            else:
-                print("error: bad command format")
-
-
-def cmd_QSetWithHexString(options, cmd, args):
-    print('%s("%s")' % (cmd[:-1], binascii.unhexlify(args)))
-
-
-def cmd_QSetWithString(options, cmd, args):
-    print('%s("%s")' % (cmd[:-1], args))
-
-
-def cmd_QSetWithUnsigned(options, cmd, args):
-    print("%s(%i)" % (cmd[:-1], int(args)))
-
-
-def rsp_qSymbol(options, cmd, cmd_args, rsp):
-    if len(rsp) == 0:
-        print("Unsupported")
-    else:
-        if rsp == "OK":
-            print("No more symbols to lookup")
-        else:
-            packet = Packet(rsp)
-            if packet.skip_exact_string("qSymbol:"):
-                symbol_name = packet.get_hex_ascii_str()
-                print('lookup_symbol("%s")' % (symbol_name))
-            else:
-                print(
-                    'error: response string should start with "qSymbol:": respnse is "%s"'
-                    % (rsp)
-                )
-
-
-def cmd_qXfer(options, cmd, args):
-    # $qXfer:features:read:target.xml:0,1ffff#14
-    print("read target special data %s" % (args))
-    return True
-
-
-def rsp_qXfer(options, cmd, cmd_args, rsp):
-    data = cmd_args.split(":")
-    if data[0] == "features":
-        if data[1] == "read":
-            filename, extension = os.path.splitext(data[2])
-            if extension == ".xml":
-                response = Packet(rsp)
-                xml_string = response.get_hex_ascii_str()
-                if xml_string:
-                    ch = xml_string[0]
-                    if ch == "l":
-                        xml_string = xml_string[1:]
-                        xml_root = ET.fromstring(xml_string)
-                        for reg_element in xml_root.findall("./feature/reg"):
-                            if not "value_regnums" in reg_element.attrib:
-                                reg_info = RegisterInfo([])
-                                if "name" in reg_element.attrib:
-                                    reg_info.info["name"] = reg_element.attrib["name"]
-                                else:
-                                    reg_info.info["name"] = "unspecified"
-                                if "encoding" in reg_element.attrib:
-                                    reg_info.info["encoding"] = reg_element.attrib[
-                                        "encoding"
-                                    ]
-                                else:
-                                    reg_info.info["encoding"] = "uint"
-                                if "offset" in reg_element.attrib:
-                                    reg_info.info["offset"] = reg_element.attrib[
-                                        "offset"
-                                    ]
-                                if "bitsize" in reg_element.attrib:
-                                    reg_info.info["bitsize"] = reg_element.attrib[
-                                        "bitsize"
-                                    ]
-                                g_register_infos.append(reg_info)
-                        print('XML for "%s":' % (data[2]))
-                        ET.dump(xml_root)
-
-
-def cmd_A(options, cmd, args):
-    print("launch process:")
-    packet = Packet(args)
-    while True:
-        arg_len = packet.get_number()
-        if arg_len == -1:
-            break
-        if not packet.skip_exact_string(","):
-            break
-        arg_idx = packet.get_number()
-        if arg_idx == -1:
-            break
-        if not packet.skip_exact_string(","):
-            break
-        arg_value = packet.get_hex_ascii_str(arg_len)
-        print('argv[%u] = "%s"' % (arg_idx, arg_value))
-
-
-def cmd_qC(options, cmd, args):
-    print("query_current_thread_id()")
-
-
-def rsp_qC(options, cmd, cmd_args, rsp):
-    packet = Packet(rsp)
-    if packet.skip_exact_string("QC"):
-        tid = packet.get_thread_id()
-        print("current_thread_id = %#x" % (tid))
-    else:
-        print("current_thread_id = old thread ID")
-
-
-def cmd_query_packet(options, cmd, args):
-    if args:
-        print("%s%s" % (cmd, args))
-    else:
-        print("%s" % (cmd))
-    return False
-
-
-def rsp_ok_error(rsp):
-    print("rsp: ", rsp)
-
-
-def rsp_ok_means_supported(options, cmd, cmd_args, rsp):
-    if rsp == "OK":
-        print("%s%s is supported" % (cmd, cmd_args))
-    elif rsp == "":
-        print("%s%s is not supported" % (cmd, cmd_args))
-    else:
-        print("%s%s -> %s" % (cmd, cmd_args, rsp))
-
-
-def rsp_ok_means_success(options, cmd, cmd_args, rsp):
-    if rsp == "OK":
-        print("success")
-    elif rsp == "":
-        print("%s%s is not supported" % (cmd, cmd_args))
-    else:
-        print("%s%s -> %s" % (cmd, cmd_args, rsp))
-
-
-def dump_key_value_pairs(key_value_pairs):
-    max_key_len = 0
-    for key_value_pair in key_value_pairs:
-        key_len = len(key_value_pair[0])
-        if max_key_len < key_len:
-            max_key_len = key_len
-    for key_value_pair in key_value_pairs:
-        key = key_value_pair[0]
-        value = key_value_pair[1]
-        unhex_value = get_hex_string_if_all_printable(value)
-        if unhex_value:
-            print("%*s = %s (%s)" % (max_key_len, key, value, unhex_value))
-        else:
-            print("%*s = %s" % (max_key_len, key, value))
-
-
-def rsp_dump_key_value_pairs(options, cmd, cmd_args, rsp):
-    if rsp:
-        print("%s response:" % (cmd))
-        packet = Packet(rsp)
-        key_value_pairs = packet.get_key_value_pairs()
-        dump_key_value_pairs(key_value_pairs)
-    else:
-        print("not supported")
-
-
-def cmd_c(options, cmd, args):
-    print("continue()")
-    return False
-
-
-def cmd_s(options, cmd, args):
-    print("step()")
-    return False
-
-
-def cmd_qSpeedTest(options, cmd, args):
-    print(("qSpeedTest: cmd='%s', args='%s'" % (cmd, args)))
-
-
-def rsp_qSpeedTest(options, cmd, cmd_args, rsp):
-    print(("qSpeedTest: rsp='%s' cmd='%s', args='%s'" % (rsp, cmd, args)))
-
-
-def cmd_vCont(options, cmd, args):
-    if args == "?":
-        print("%s: get supported extended continue modes" % (cmd))
-    else:
-        got_other_threads = 0
-        s = ""
-        for thread_action in args[1:].split(";"):
-            (short_action, thread) = thread_action.split(":", 1)
-            tid = int(thread, 16)
-            if short_action == "c":
-                action = "continue"
-            elif short_action == "s":
-                action = "step"
-            elif short_action[0] == "C":
-                action = "continue with signal 0x%s" % (short_action[1:])
-            elif short_action == "S":
-                action = "step with signal 0x%s" % (short_action[1:])
-            else:
-                action = short_action
-            if s:
-                s += ", "
-            if tid == -1:
-                got_other_threads = 1
-                s += "other-threads:"
-            else:
-                s += "thread 0x%4.4x: %s" % (tid, action)
-        if got_other_threads:
-            print("extended_continue (%s)" % (s))
-        else:
-            print("extended_continue (%s, other-threads: suspend)" % (s))
-    return False
-
-
-def rsp_vCont(options, cmd, cmd_args, rsp):
-    if cmd_args == "?":
-        # Skip the leading 'vCont;'
-        rsp = rsp[6:]
-        modes = rsp.split(";")
-        s = "%s: supported extended continue modes include: " % (cmd)
-
-        for i, mode in enumerate(modes):
-            if i:
-                s += ", "
-            if mode == "c":
-                s += "continue"
-            elif mode == "C":
-                s += "continue with signal"
-            elif mode == "s":
-                s += "step"
-            elif mode == "S":
-                s += "step with signal"
-            elif mode == "t":
-                s += "stop"
-            # else:
-            #     s += 'unrecognized vCont mode: ', str(mode)
-        print(s)
-    elif rsp:
-        if rsp[0] == "T" or rsp[0] == "S" or rsp[0] == "W" or rsp[0] == "X":
-            rsp_stop_reply(options, cmd, cmd_args, rsp)
-            return
-        if rsp[0] == "O":
-            print("stdout: %s" % (rsp))
-            return
-    else:
-        print(
-            "not supported (cmd = '%s', args = '%s', rsp = '%s')" % (cmd, cmd_args, rsp)
-        )
-
-
-def cmd_vAttach(options, cmd, args):
-    (extra_command, args) = args.split(";")
-    if extra_command:
-        print("%s%s(%s)" % (cmd, extra_command, args))
-    else:
-        print("attach(pid = %u)" % int(args, 16))
-    return False
-
-
-def cmd_qRegisterInfo(options, cmd, args):
-    print("query_register_info(reg_num=%i)" % (int(args, 16)))
-    return False
-
-
-def rsp_qRegisterInfo(options, cmd, cmd_args, rsp):
-    global g_max_register_info_name_len
-    print("query_register_info(reg_num=%i):" % (int(cmd_args, 16)), end=" ")
-    if len(rsp) == 3 and rsp[0] == "E":
-        g_max_register_info_name_len = 0
-        for reg_info in g_register_infos:
-            name_len = len(reg_info.name())
-            if g_max_register_info_name_len < name_len:
-                g_max_register_info_name_len = name_len
-        print(" DONE")
-    else:
-        packet = Packet(rsp)
-        reg_info = RegisterInfo(packet.get_key_value_pairs())
-        g_register_infos.append(reg_info)
-        print(reg_info)
-    return False
-
-
-def cmd_qThreadInfo(options, cmd, args):
-    if cmd == "qfThreadInfo":
-        query_type = "first"
-    else:
-        query_type = "subsequent"
-    print("get_current_thread_list(type=%s)" % (query_type))
-    return False
-
-
-def rsp_qThreadInfo(options, cmd, cmd_args, rsp):
-    packet = Packet(rsp)
-    response_type = packet.get_char()
-    if response_type == "m":
-        tids = packet.split_hex(";", "big")
-        for i, tid in enumerate(tids):
-            if i:
-                print(",", end=" ")
-            print("0x%x" % (tid), end=" ")
-        print()
-    elif response_type == "l":
-        print("END")
-
-
-def rsp_hex_big_endian(options, cmd, cmd_args, rsp):
-    if rsp == "":
-        print("%s%s is not supported" % (cmd, cmd_args))
-    else:
-        packet = Packet(rsp)
-        uval = packet.get_hex_uint("big")
-        print("%s: 0x%x" % (cmd, uval))
-
-
-def cmd_read_mem_bin(options, cmd, args):
-    # x0x7fff5fc39200,0x200
-    packet = Packet(args)
-    addr = packet.get_hex_uint("big")
-    comma = packet.get_char()
-    size = packet.get_hex_uint("big")
-    print("binary_read_memory (addr = 0x%16.16x, size = %u)" % (addr, size))
-    return False
-
-
-def rsp_mem_bin_bytes(options, cmd, cmd_args, rsp):
-    packet = Packet(cmd_args)
-    addr = packet.get_hex_uint("big")
-    comma = packet.get_char()
-    size = packet.get_hex_uint("big")
-    print("memory:")
-    if size > 0:
-        dump_hex_memory_buffer(addr, rsp)
-
-
-def cmd_read_memory(options, cmd, args):
-    packet = Packet(args)
-    addr = packet.get_hex_uint("big")
-    comma = packet.get_char()
-    size = packet.get_hex_uint("big")
-    print("read_memory (addr = 0x%16.16x, size = %u)" % (addr, size))
-    return False
-
-
-def dump_hex_memory_buffer(addr, hex_byte_str):
-    packet = Packet(hex_byte_str)
-    idx = 0
-    ascii = ""
-    uval = packet.get_hex_uint8()
-    while uval is not None:
-        if (idx % 16) == 0:
-            if ascii:
-                print("  ", ascii)
-                ascii = ""
-            print("0x%x:" % (addr + idx), end=" ")
-        print("%2.2x" % (uval), end=" ")
-        if 0x20 <= uval and uval < 0x7F:
-            ascii += "%c" % uval
-        else:
-            ascii += "."
-        uval = packet.get_hex_uint8()
-        idx = idx + 1
-    if ascii:
-        print("  ", ascii)
-        ascii = ""
-
-
-def cmd_write_memory(options, cmd, args):
-    packet = Packet(args)
-    addr = packet.get_hex_uint("big")
-    if packet.get_char() != ",":
-        print("error: invalid write memory command (missing comma after address)")
-        return
-    size = packet.get_hex_uint("big")
-    if packet.get_char() != ":":
-        print("error: invalid write memory command (missing colon after size)")
-        return
-    print("write_memory (addr = 0x%16.16x, size = %u, data:" % (addr, size))
-    dump_hex_memory_buffer(addr, packet.str)
-    return False
-
-
-def cmd_alloc_memory(options, cmd, args):
-    packet = Packet(args)
-    byte_size = packet.get_hex_uint("big")
-    if packet.get_char() != ",":
-        print("error: invalid allocate memory command (missing comma after address)")
-        return
-    print(
-        "allocate_memory (byte-size = %u (0x%x), permissions = %s)"
-        % (byte_size, byte_size, packet.str)
-    )
-    return False
-
-
-def rsp_alloc_memory(options, cmd, cmd_args, rsp):
-    packet = Packet(rsp)
-    addr = packet.get_hex_uint("big")
-    print("addr = 0x%x" % addr)
-
-
-def cmd_dealloc_memory(options, cmd, args):
-    packet = Packet(args)
-    addr = packet.get_hex_uint("big")
-    if packet.get_char() != ",":
-        print("error: invalid allocate memory command (missing comma after address)")
-    else:
-        print("deallocate_memory (addr = 0x%x, permissions = %s)" % (addr, packet.str))
-    return False
-
-
-def rsp_memory_bytes(options, cmd, cmd_args, rsp):
-    addr = Packet(cmd_args).get_hex_uint("big")
-    dump_hex_memory_buffer(addr, rsp)
-
-
-def get_register_name_equal_value(options, reg_num, hex_value_str):
-    if reg_num < len(g_register_infos):
-        reg_info = g_register_infos[reg_num]
-        value_str = reg_info.get_value_from_hex_string(hex_value_str)
-        s = reg_info.name() + " = "
-        if options.symbolicator:
-            symbolicated_addresses = options.symbolicator.symbolicate(int(value_str, 0))
-            if symbolicated_addresses:
-                s += options.colors.magenta()
-                s += "%s" % symbolicated_addresses[0]
-                s += options.colors.reset()
-                return s
-        s += value_str
-        return s
-    else:
-        reg_value = Packet(hex_value_str).get_hex_uint(g_byte_order)
-        return "reg(%u) = 0x%x" % (reg_num, reg_value)
-
-
-def cmd_read_one_reg(options, cmd, args):
-    packet = Packet(args)
-    reg_num = packet.get_hex_uint("big")
-    tid = get_thread_from_thread_suffix(packet.str)
-    name = None
-    if reg_num < len(g_register_infos):
-        name = g_register_infos[reg_num].name()
-    if packet.str:
-        packet.get_char()  # skip ;
-        thread_info = packet.get_key_value_pairs()
-        tid = int(thread_info[0][1], 16)
-    s = "read_register (reg_num=%u" % reg_num
-    if name:
-        s += " (%s)" % (name)
-    if tid is not None:
-        s += ", tid = 0x%4.4x" % (tid)
-    s += ")"
-    print(s)
-    return False
-
-
-def rsp_read_one_reg(options, cmd, cmd_args, rsp):
-    packet = Packet(cmd_args)
-    reg_num = packet.get_hex_uint("big")
-    print(get_register_name_equal_value(options, reg_num, rsp))
-
-
-def cmd_write_one_reg(options, cmd, args):
-    packet = Packet(args)
-    reg_num = packet.get_hex_uint("big")
-    if packet.get_char() != "=":
-        print("error: invalid register write packet")
-    else:
-        name = None
-        hex_value_str = packet.get_hex_chars()
-        tid = get_thread_from_thread_suffix(packet.str)
-        s = "write_register (reg_num=%u" % reg_num
-        if name:
-            s += " (%s)" % (name)
-        s += ", value = "
-        s += get_register_name_equal_value(options, reg_num, hex_value_str)
-        if tid is not None:
-            s += ", tid = 0x%4.4x" % (tid)
-        s += ")"
-        print(s)
-    return False
-
-
-def dump_all_regs(packet):
-    for reg_info in g_register_infos:
-        nibble_size = reg_info.bit_size() / 4
-        hex_value_str = packet.get_hex_chars(nibble_size)
-        if hex_value_str is not None:
-            value = reg_info.get_value_from_hex_string(hex_value_str)
-            print("%*s = %s" % (g_max_register_info_name_len, reg_info.name(), value))
-        else:
-            return
-
-
-def cmd_read_all_regs(cmd, cmd_args):
-    packet = Packet(cmd_args)
-    packet.get_char()  # toss the 'g' command character
-    tid = get_thread_from_thread_suffix(packet.str)
-    if tid is not None:
-        print("read_all_register(thread = 0x%4.4x)" % tid)
-    else:
-        print("read_all_register()")
-    return False
-
-
-def rsp_read_all_regs(options, cmd, cmd_args, rsp):
-    packet = Packet(rsp)
-    dump_all_regs(packet)
-
-
-def cmd_write_all_regs(options, cmd, args):
-    packet = Packet(args)
-    print("write_all_registers()")
-    dump_all_regs(packet)
-    return False
-
-
-g_bp_types = ["software_bp", "hardware_bp", "write_wp", "read_wp", "access_wp"]
-
-
-def cmd_bp(options, cmd, args):
-    if cmd == "Z":
-        s = "set_"
-    else:
-        s = "clear_"
-    packet = Packet(args)
-    bp_type = packet.get_hex_uint("big")
-    packet.get_char()  # Skip ,
-    bp_addr = packet.get_hex_uint("big")
-    packet.get_char()  # Skip ,
-    bp_size = packet.get_hex_uint("big")
-    s += g_bp_types[bp_type]
-    s += " (addr = 0x%x, size = %u)" % (bp_addr, bp_size)
-    print(s)
-    return False
-
-
-def cmd_mem_rgn_info(options, cmd, args):
-    packet = Packet(args)
-    packet.get_char()  # skip ':' character
-    addr = packet.get_hex_uint("big")
-    print("get_memory_region_info (addr=0x%x)" % (addr))
-    return False
-
-
-def cmd_kill(options, cmd, args):
-    print("kill_process()")
-    return False
-
-
-def cmd_jThreadsInfo(options, cmd, args):
-    print("jThreadsInfo()")
-    return False
-
-
-def cmd_jGetLoadedDynamicLibrariesInfos(options, cmd, args):
-    print("jGetLoadedDynamicLibrariesInfos()")
-    return False
-
-
-def decode_packet(s, start_index=0):
-    # print '\ndecode_packet("%s")' % (s[start_index:])
-    index = s.find("}", start_index)
-    have_escapes = index != -1
-    if have_escapes:
-        normal_s = s[start_index:index]
-    else:
-        normal_s = s[start_index:]
-    # print 'normal_s = "%s"' % (normal_s)
-    if have_escapes:
-        escape_char = "%c" % (ord(s[index + 1]) ^ 0x20)
-        # print 'escape_char for "%s" = %c' % (s[index:index+2], escape_char)
-        return normal_s + escape_char + decode_packet(s, index + 2)
-    else:
-        return normal_s
-
-
-def rsp_json(options, cmd, cmd_args, rsp):
-    print("%s() reply:" % (cmd))
-    if not rsp:
-        return
-    try:
-        json_tree = json.loads(rsp)
-        print(json.dumps(json_tree, indent=4, separators=(",", ": ")))
-    except json.JSONDecodeError:
-        return
-
-
-def rsp_jGetLoadedDynamicLibrariesInfos(options, cmd, cmd_args, rsp):
-    if cmd_args:
-        rsp_json(options, cmd, cmd_args, rsp)
-    else:
-        rsp_ok_means_supported(options, cmd, cmd_args, rsp)
-
-
-gdb_remote_commands = {
-    "\\?": {"cmd": cmd_stop_reply, "rsp": rsp_stop_reply, "name": "stop reply pacpket"},
-    "qThreadStopInfo": {
-        "cmd": cmd_qThreadStopInfo,
-        "rsp": rsp_stop_reply,
-        "name": "stop reply pacpket",
-    },
-    "QStartNoAckMode": {
-        "cmd": cmd_query_packet,
-        "rsp": rsp_ok_means_supported,
-        "name": "query if no ack mode is supported",
-    },
-    "QThreadSuffixSupported": {
-        "cmd": cmd_query_packet,
-        "rsp": rsp_ok_means_supported,
-        "name": "query if thread suffix is supported",
-    },
-    "QListThreadsInStopReply": {
-        "cmd": cmd_query_packet,
-        "rsp": rsp_ok_means_supported,
-        "name": "query if threads in stop reply packets are supported",
-    },
-    "QSetDetachOnError:": {
-        "cmd": cmd_QSetWithUnsigned,
-        "rsp": rsp_ok_means_success,
-        "name": "set if we should detach on error",
-    },
-    "QSetDisableASLR:": {
-        "cmd": cmd_QSetWithUnsigned,
-        "rsp": rsp_ok_means_success,
-        "name": "set if we should disable ASLR",
-    },
-    "qLaunchSuccess": {
-        "cmd": cmd_query_packet,
-        "rsp": rsp_ok_means_success,
-        "name": "check on launch success for the A packet",
-    },
-    "A": {"cmd": cmd_A, "rsp": rsp_ok_means_success, "name": "launch process"},
-    "QLaunchArch:": {
-        "cmd": cmd_QSetWithString,
-        "rsp": rsp_ok_means_supported,
-        "name": "set the arch to launch in case the file contains multiple architectures",
-    },
-    "qVAttachOrWaitSupported": {
-        "cmd": cmd_query_packet,
-        "rsp": rsp_ok_means_supported,
-        "name": "set the launch architecture",
-    },
-    "qHostInfo": {
-        "cmd": cmd_query_packet,
-        "rsp": rsp_dump_key_value_pairs,
-        "name": "get host information",
-    },
-    "qC": {"cmd": cmd_qC, "rsp": rsp_qC, "name": "return the current thread ID"},
-    "vCont": {"cmd": cmd_vCont, "rsp": rsp_vCont, "name": "extended continue command"},
-    "qSpeedTest": {
-        "cmd": cmd_qSpeedTest,
-        "rsp": rsp_qSpeedTest,
-        "name": "speed test packdet",
-    },
-    "vAttach": {"cmd": cmd_vAttach, "rsp": rsp_stop_reply, "name": "attach to process"},
-    "c": {"cmd": cmd_c, "rsp": rsp_stop_reply, "name": "continue"},
-    "s": {"cmd": cmd_s, "rsp": rsp_stop_reply, "name": "step"},
-    "qRegisterInfo": {
-        "cmd": cmd_qRegisterInfo,
-        "rsp": rsp_qRegisterInfo,
-        "name": "query register info",
-    },
-    "qfThreadInfo": {
-        "cmd": cmd_qThreadInfo,
-        "rsp": rsp_qThreadInfo,
-        "name": "get current thread list",
-    },
-    "qsThreadInfo": {
-        "cmd": cmd_qThreadInfo,
-        "rsp": rsp_qThreadInfo,
-        "name": "get current thread list",
-    },
-    "qShlibInfoAddr": {
-        "cmd": cmd_query_packet,
-        "rsp": rsp_hex_big_endian,
-        "name": "get shared library info address",
-    },
-    "qMemoryRegionInfo": {
-        "cmd": cmd_mem_rgn_info,
-        "rsp": rsp_dump_key_value_pairs,
-        "name": "get memory region information",
-    },
-    "qProcessInfo": {
-        "cmd": cmd_query_packet,
-        "rsp": rsp_dump_key_value_pairs,
-        "name": "get process info",
-    },
-    "qSupported": {
-        "cmd": cmd_query_packet,
-        "rsp": rsp_ok_means_supported,
-        "name": "query supported",
-    },
-    "qXfer:": {"cmd": cmd_qXfer, "rsp": rsp_qXfer, "name": "qXfer"},
-    "qSymbol:": {"cmd": cmd_qSymbol, "rsp": rsp_qSymbol, "name": "qSymbol"},
-    "QSetSTDIN:": {
-        "cmd": cmd_QSetWithHexString,
-        "rsp": rsp_ok_means_success,
-        "name": "set STDIN prior to launching with A packet",
-    },
-    "QSetSTDOUT:": {
-        "cmd": cmd_QSetWithHexString,
-        "rsp": rsp_ok_means_success,
-        "name": "set STDOUT prior to launching with A packet",
-    },
-    "QSetSTDERR:": {
-        "cmd": cmd_QSetWithHexString,
-        "rsp": rsp_ok_means_success,
-        "name": "set STDERR prior to launching with A packet",
-    },
-    "QEnvironment:": {
-        "cmd": cmd_QSetWithString,
-        "rsp": rsp_ok_means_success,
-        "name": "set an environment variable prior to launching with A packet",
-    },
-    "QEnvironmentHexEncoded:": {
-        "cmd": cmd_QSetWithHexString,
-        "rsp": rsp_ok_means_success,
-        "name": "set an environment variable prior to launching with A packet",
-    },
-    "x": {
-        "cmd": cmd_read_mem_bin,
-        "rsp": rsp_mem_bin_bytes,
-        "name": "read memory binary",
-    },
-    "X": {
-        "cmd": cmd_write_memory,
-        "rsp": rsp_ok_means_success,
-        "name": "write memory binary",
-    },
-    "m": {"cmd": cmd_read_memory, "rsp": rsp_memory_bytes, "name": "read memory"},
-    "M": {"cmd": cmd_write_memory, "rsp": rsp_ok_means_success, "name": "write memory"},
-    "_M": {"cmd": cmd_alloc_memory, "rsp": rsp_alloc_memory, "name": "allocate memory"},
-    "_m": {
-        "cmd": cmd_dealloc_memory,
-        "rsp": rsp_ok_means_success,
-        "name": "deallocate memory",
-    },
-    "p": {
-        "cmd": cmd_read_one_reg,
-        "rsp": rsp_read_one_reg,
-        "name": "read single register",
-    },
-    "P": {
-        "cmd": cmd_write_one_reg,
-        "rsp": rsp_ok_means_success,
-        "name": "write single register",
-    },
-    "g": {
-        "cmd": cmd_read_all_regs,
-        "rsp": rsp_read_all_regs,
-        "name": "read all registers",
-    },
-    "G": {
-        "cmd": cmd_write_all_regs,
-        "rsp": rsp_ok_means_success,
-        "name": "write all registers",
-    },
-    "z": {
-        "cmd": cmd_bp,
-        "rsp": rsp_ok_means_success,
-        "name": "clear breakpoint or watchpoint",
-    },
-    "Z": {
-        "cmd": cmd_bp,
-        "rsp": rsp_ok_means_success,
-        "name": "set breakpoint or watchpoint",
-    },
-    "k": {"cmd": cmd_kill, "rsp": rsp_stop_reply, "name": "kill process"},
-    "jThreadsInfo": {
-        "cmd": cmd_jThreadsInfo,
-        "rsp": rsp_json,
-        "name": "JSON get all threads info",
-    },
-    "jGetLoadedDynamicLibrariesInfos:": {
-        "cmd": cmd_jGetLoadedDynamicLibrariesInfos,
-        "rsp": rsp_jGetLoadedDynamicLibrariesInfos,
-        "name": "JSON get loaded dynamic libraries",
-    },
-}
-
-
-def calculate_mean_and_standard_deviation(floats):
-    sum = 0.0
-    count = len(floats)
-    if count == 0:
-        return (0.0, 0.0)
-    for f in floats:
-        sum += f
-    mean = sum / count
-    accum = 0.0
-    for f in floats:
-        delta = f - mean
-        accum += delta * delta
-
-    std_dev = math.sqrt(accum / (count - 1))
-    return (mean, std_dev)
-
-
-def parse_gdb_log_file(path, options):
-    f = open(path)
-    parse_gdb_log(f, options)
-    f.close()
-
-
-def round_up(n, incr):
-    return float(((int(n) + incr) / incr) * incr)
-
-
-def plot_latencies(sec_times):
-    # import numpy as np
-    import matplotlib.pyplot as plt
-
-    for i, name in enumerate(sec_times.keys()):
-        times = sec_times[name]
-        if len(times) <= 1:
-            continue
-        plt.subplot(2, 1, 1)
-        plt.title('Packet "%s" Times' % (name))
-        plt.xlabel("Packet")
-        units = "ms"
-        adj_times = []
-        max_time = 0.0
-        for time in times:
-            time = time * 1000.0
-            adj_times.append(time)
-            if time > max_time:
-                max_time = time
-        if max_time < 1.0:
-            units = "us"
-            max_time = 0.0
-            for i in range(len(adj_times)):
-                adj_times[i] *= 1000.0
-                if adj_times[i] > max_time:
-                    max_time = adj_times[i]
-        plt.ylabel("Time (%s)" % (units))
-        max_y = None
-        for i in [5.0, 10.0, 25.0, 50.0]:
-            if max_time < i:
-                max_y = round_up(max_time, i)
-                break
-        if max_y is None:
-            max_y = round_up(max_time, 100.0)
-        plt.ylim(0.0, max_y)
-        plt.plot(adj_times, "o-")
-        plt.show()
-
-
-def parse_gdb_log(file, options):
-    """Parse a GDB log file that was generated by enabling logging with:
-    (lldb) log enable --threadsafe --timestamp --file <FILE> gdb-remote packets
-    This log file will contain timestamps and this function will then normalize
-    those packets to be relative to the first value timestamp that is found and
-    show delta times between log lines and also keep track of how long it takes
-    for GDB remote commands to make a send/receive round trip. This can be
-    handy when trying to figure out why some operation in the debugger is taking
-    a long time during a preset set of debugger commands."""
-
-    tricky_commands = ["qRegisterInfo"]
-    timestamp_regex = re.compile(r"(\s*)([1-9][0-9]+\.[0-9]+)([^0-9].*)$")
-    packet_name_regex = re.compile("([A-Za-z_]+)[^a-z]")
-    packet_transmit_name_regex = re.compile(
-        "(?P<direction>send|read) packet: (?P<packet>.*)"
-    )
-    packet_contents_name_regex = re.compile(r"\$([^#]*)#[0-9a-fA-F]{2}")
-    packet_checksum_regex = re.compile(".*#[0-9a-fA-F]{2}$")
-    packet_names_regex_str = "(" + "|".join(gdb_remote_commands.keys()) + ")(.*)"
-    packet_names_regex = re.compile(packet_names_regex_str)
-
-    base_time = 0.0
-    last_time = 0.0
-    min_time = 100000000.0
-    packet_total_times = {}
-    all_packet_times = []
-    packet_times = {}
-    packet_counts = {}
-    lines = file.read().splitlines()
-    last_command = None
-    last_command_args = None
-    last_command_packet = None
-    hide_next_response = False
-    num_lines = len(lines)
-    skip_count = 0
-    for line_index, line in enumerate(lines):
-        # See if we need to skip any lines
-        if skip_count > 0:
-            skip_count -= 1
-            continue
-        m = packet_transmit_name_regex.search(line)
-        is_command = False
-        direction = None
-        if m:
-            direction = m.group("direction")
-            is_command = direction == "send"
-            packet = m.group("packet")
-            sys.stdout.write(options.colors.green())
-            if not options.quiet and not hide_next_response:
-                print("#  ", line)
-            sys.stdout.write(options.colors.reset())
-
-            # print 'direction = "%s", packet = "%s"' % (direction, packet)
-
-            if packet[0] == "+":
-                if is_command:
-                    print("-->", end=" ")
-                else:
-                    print("<--", end=" ")
-                if not options.quiet:
-                    print("ACK")
-                continue
-            elif packet[0] == "-":
-                if is_command:
-                    print("-->", end=" ")
-                else:
-                    print("<--", end=" ")
-                if not options.quiet:
-                    print("NACK")
-                continue
-            elif packet[0] == "$":
-                m = packet_contents_name_regex.match(packet)
-                if not m and packet[0] == "$":
-                    multiline_packet = packet
-                    idx = line_index + 1
-                    while idx < num_lines:
-                        if not options.quiet and not hide_next_response:
-                            print("#  ", lines[idx])
-                        multiline_packet += lines[idx]
-                        m = packet_contents_name_regex.match(multiline_packet)
-                        if m:
-                            packet = multiline_packet
-                            skip_count = idx - line_index
-                            break
-                        else:
-                            idx += 1
-                if m:
-                    if is_command:
-                        print("-->", end=" ")
-                    else:
-                        print("<--", end=" ")
-                    contents = decode_packet(m.group(1))
-                    if is_command:
-                        hide_next_response = False
-                        m = packet_names_regex.match(contents)
-                        if m:
-                            last_command = m.group(1)
-                            if last_command == "?":
-                                last_command = "\\?"
-                            packet_name = last_command
-                            last_command_args = m.group(2)
-                            last_command_packet = contents
-                            hide_next_response = gdb_remote_commands[last_command][
-                                "cmd"
-                            ](options, last_command, last_command_args)
-                        else:
-                            packet_match = packet_name_regex.match(contents)
-                            if packet_match:
-                                packet_name = packet_match.group(1)
-                                for tricky_cmd in tricky_commands:
-                                    if packet_name.find(tricky_cmd) == 0:
-                                        packet_name = tricky_cmd
-                            else:
-                                packet_name = contents
-                            last_command = None
-                            last_command_args = None
-                            last_command_packet = None
-                    elif last_command:
-                        gdb_remote_commands[last_command]["rsp"](
-                            options, last_command, last_command_args, contents
-                        )
-                else:
-                    print('error: invalid packet: "', packet, '"')
-            else:
-                print("???")
-        else:
-            print("## ", line)
-        match = timestamp_regex.match(line)
-        if match:
-            curr_time = float(match.group(2))
-            if last_time and not is_command:
-                delta = curr_time - last_time
-                all_packet_times.append(delta)
-            delta = 0.0
-            if base_time:
-                delta = curr_time - last_time
-            else:
-                base_time = curr_time
-
-            if not is_command:
-                if line.find("read packet: $") >= 0 and packet_name:
-                    if packet_name in packet_total_times:
-                        packet_total_times[packet_name] += delta
-                        packet_counts[packet_name] += 1
-                    else:
-                        packet_total_times[packet_name] = delta
-                        packet_counts[packet_name] = 1
-                    if packet_name not in packet_times:
-                        packet_times[packet_name] = []
-                    packet_times[packet_name].append(delta)
-                    packet_name = None
-                if min_time > delta:
-                    min_time = delta
-
-            if not options or not options.quiet:
-                print(
-                    "%s%.6f %+.6f%s"
-                    % (match.group(1), curr_time - base_time, delta, match.group(3))
-                )
-            last_time = curr_time
-        # else:
-        #     print line
-    (average, std_dev) = calculate_mean_and_standard_deviation(all_packet_times)
-    if average and std_dev:
-        print(
-            "%u packets with average packet time of %f and standard deviation of %f"
-            % (len(all_packet_times), average, std_dev)
-        )
-    if packet_total_times:
-        total_packet_time = 0.0
-        total_packet_count = 0
-        for key, vvv in packet_total_times.items():
-            # print '  key = (%s) "%s"' % (type(key), key)
-            # print 'value = (%s) %s' % (type(vvv), vvv)
-            # if type(vvv) == 'float':
-            total_packet_time += vvv
-        for key, vvv in packet_counts.items():
-            total_packet_count += vvv
-
-        print("#------------------------------------------------------------")
-        print("# Packet timing summary:")
-        print(
-            "# Totals: time = %6f, count = %6d"
-            % (total_packet_time, total_packet_count)
-        )
-        print("# Min packet time: time = %6f" % (min_time))
-        print("#------------------------------------------------------------")
-        print("# Packet                   Time (sec)  Percent Count  Latency")
-        print("#------------------------- ----------- ------- ------ -------")
-        if options and options.sort_count:
-            res = sorted(packet_counts, key=packet_counts.__getitem__, reverse=True)
-        else:
-            res = sorted(
-                packet_total_times, key=packet_total_times.__getitem__, reverse=True
-            )
-
-        if last_time > 0.0:
-            for item in res:
-                packet_total_time = packet_total_times[item]
-                packet_percent = (packet_total_time / total_packet_time) * 100.0
-                packet_count = packet_counts[item]
-                print(
-                    "  %24s %11.6f  %5.2f%% %6d %9.6f"
-                    % (
-                        item,
-                        packet_total_time,
-                        packet_percent,
-                        packet_count,
-                        float(packet_total_time) / float(packet_count),
-                    )
-                )
-        if options and options.plot:
-            plot_latencies(packet_times)
-
-
-if __name__ == "__main__":
-    usage = "usage: gdbremote [options]"
-    description = """The command disassembles a GDB remote packet log."""
-    parser = optparse.OptionParser(
-        description=description, prog="gdbremote", usage=usage
-    )
-    parser.add_option(
-        "-v",
-        "--verbose",
-        action="store_true",
-        dest="verbose",
-        help="display verbose debug info",
-        default=False,
-    )
-    parser.add_option(
-        "-q",
-        "--quiet",
-        action="store_true",
-        dest="quiet",
-        help="display verbose debug info",
-        default=False,
-    )
-    parser.add_option(
-        "-C",
-        "--color",
-        action="store_true",
-        dest="color",
-        help="add terminal colors",
-        default=False,
-    )
-    parser.add_option(
-        "-c",
-        "--sort-by-count",
-        action="store_true",
-        dest="sort_count",
-        help="display verbose debug info",
-        default=False,
-    )
-    parser.add_option(
-        "--crashlog",
-        type="string",
-        dest="crashlog",
-        help="symbolicate using a darwin crash log file",
-        default=False,
-    )
-    try:
-        (options, args) = parser.parse_args(sys.argv[1:])
-    except:
-        print("error: argument error")
-        sys.exit(1)
-
-    options.colors = TerminalColors(options.color)
-    options.symbolicator = None
-    if options.crashlog:
-        import lldb
-
-        lldb.debugger = lldb.SBDebugger.Create()
-        import lldb.macosx.crashlog
-
-        options.symbolicator = lldb.macosx.crashlog.CrashLog(options.crashlog)
-        print("%s" % (options.symbolicator))
-
-    # This script is being run from the command line, create a debugger in case we are
-    # going to use any debugger functions in our function.
-    if len(args):
-        for file in args:
-            print(
-                "#----------------------------------------------------------------------"
-            )
-            print("# GDB remote log file: '%s'" % file)
-            print(
-                "#----------------------------------------------------------------------"
-            )
-            parse_gdb_log_file(file, options)
-        if options.symbolicator:
-            print("%s" % (options.symbolicator))
-    else:
-        parse_gdb_log(sys.stdin, options)
-
-
-def __lldb_init_module(debugger, internal_dict):
-    # This initializer is being run from LLDB in the embedded command interpreter
-    # Add any commands contained in this module to LLDB
-    debugger.HandleCommand(
-        "command script add -o -f gdbremote.start_gdb_log start_gdb_log"
-    )
-    debugger.HandleCommand(
-        "command script add -o -f gdbremote.stop_gdb_log stop_gdb_log"
-    )
-    print(
-        'The "start_gdb_log" and "stop_gdb_log" commands are now installed and ready for use, type "start_gdb_log --help" or "stop_gdb_log --help" for more information'
-    )
+#!/usr/bin/env python
+
+# ----------------------------------------------------------------------
+# This module will enable GDB remote packet logging when the
+# 'start_gdb_log' command is called with a filename to log to. When the
+# 'stop_gdb_log' command is called, it will disable the logging and
+# print out statistics about how long commands took to execute and also
+# will primnt ou
+# Be sure to add the python path that points to the LLDB shared library.
+#
+# To use this in the embedded python interpreter using "lldb" just
+# import it with the full path using the "command script import"
+# command. This can be done from the LLDB command line:
+#   (lldb) command script import /path/to/gdbremote.py
+# Or it can be added to your ~/.lldbinit file so this module is always
+# available.
+# ----------------------------------------------------------------------
+
+import binascii
+import subprocess
+import json
+import math
+import optparse
+import os
+import re
+import shlex
+import string
+import sys
+import tempfile
+import xml.etree.ElementTree as ET
+
+# ----------------------------------------------------------------------
+# Global variables
+# ----------------------------------------------------------------------
+g_log_file = ""
+g_byte_order = "little"
+g_number_regex = re.compile("^(0x[0-9a-fA-F]+|[0-9]+)")
+g_thread_id_regex = re.compile("^(-1|[0-9a-fA-F]+|0)")
+
+
+class TerminalColors:
+    """Simple terminal colors class"""
+
+    def __init__(self, enabled=True):
+        # TODO: discover terminal type from "file" and disable if
+        # it can't handle the color codes
+        self.enabled = enabled
+
+    def reset(self):
+        """Reset all terminal colors and formatting."""
+        if self.enabled:
+            return "\x1b[0m"
+        return ""
+
+    def bold(self, on=True):
+        """Enable or disable bold depending on the "on" parameter."""
+        if self.enabled:
+            if on:
+                return "\x1b[1m"
+            else:
+                return "\x1b[22m"
+        return ""
+
+    def italics(self, on=True):
+        """Enable or disable italics depending on the "on" parameter."""
+        if self.enabled:
+            if on:
+                return "\x1b[3m"
+            else:
+                return "\x1b[23m"
+        return ""
+
+    def underline(self, on=True):
+        """Enable or disable underline depending on the "on" parameter."""
+        if self.enabled:
+            if on:
+                return "\x1b[4m"
+            else:
+                return "\x1b[24m"
+        return ""
+
+    def inverse(self, on=True):
+        """Enable or disable inverse depending on the "on" parameter."""
+        if self.enabled:
+            if on:
+                return "\x1b[7m"
+            else:
+                return "\x1b[27m"
+        return ""
+
+    def strike(self, on=True):
+        """Enable or disable strike through depending on the "on" parameter."""
+        if self.enabled:
+            if on:
+                return "\x1b[9m"
+            else:
+                return "\x1b[29m"
+        return ""
+
+    def black(self, fg=True):
+        """Set the foreground or background color to black.
+        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.
+        """
+        if self.enabled:
+            if fg:
+                return "\x1b[30m"
+            else:
+                return "\x1b[40m"
+        return ""
+
+    def red(self, fg=True):
+        """Set the foreground or background color to red.
+        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.
+        """
+        if self.enabled:
+            if fg:
+                return "\x1b[31m"
+            else:
+                return "\x1b[41m"
+        return ""
+
+    def green(self, fg=True):
+        """Set the foreground or background color to green.
+        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.
+        """
+        if self.enabled:
+            if fg:
+                return "\x1b[32m"
+            else:
+                return "\x1b[42m"
+        return ""
+
+    def yellow(self, fg=True):
+        """Set the foreground or background color to yellow.
+        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.
+        """
+        if self.enabled:
+            if fg:
+                return "\x1b[33m"
+            else:
+                return "\x1b[43m"
+        return ""
+
+    def blue(self, fg=True):
+        """Set the foreground or background color to blue.
+        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.
+        """
+        if self.enabled:
+            if fg:
+                return "\x1b[34m"
+            else:
+                return "\x1b[44m"
+        return ""
+
+    def magenta(self, fg=True):
+        """Set the foreground or background color to magenta.
+        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.
+        """
+        if self.enabled:
+            if fg:
+                return "\x1b[35m"
+            else:
+                return "\x1b[45m"
+        return ""
+
+    def cyan(self, fg=True):
+        """Set the foreground or background color to cyan.
+        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.
+        """
+        if self.enabled:
+            if fg:
+                return "\x1b[36m"
+            else:
+                return "\x1b[46m"
+        return ""
+
+    def white(self, fg=True):
+        """Set the foreground or background color to white.
+        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.
+        """
+        if self.enabled:
+            if fg:
+                return "\x1b[37m"
+            else:
+                return "\x1b[47m"
+        return ""
+
+    def default(self, fg=True):
+        """Set the foreground or background color to the default.
+        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.
+        """
+        if self.enabled:
+            if fg:
+                return "\x1b[39m"
+            else:
+                return "\x1b[49m"
+        return ""
+
+
+def start_gdb_log(debugger, command, result, dict):
+    """Start logging GDB remote packets by enabling logging with timestamps and
+    thread safe logging. Follow a call to this function with a call to "stop_gdb_log"
+    in order to dump out the commands."""
+    global g_log_file
+    command_args = shlex.split(command)
+    usage = "usage: start_gdb_log [options] [<LOGFILEPATH>]"
+    description = """The command enables GDB remote packet logging with timestamps. The packets will be logged to <LOGFILEPATH> if supplied, or a temporary file will be used. Logging stops when stop_gdb_log is called and the packet times will
+    be aggregated and displayed."""
+    parser = optparse.OptionParser(
+        description=description, prog="start_gdb_log", usage=usage
+    )
+    parser.add_option(
+        "-v",
+        "--verbose",
+        action="store_true",
+        dest="verbose",
+        help="display verbose debug info",
+        default=False,
+    )
+    try:
+        (options, args) = parser.parse_args(command_args)
+    except:
+        return
+
+    if g_log_file:
+        result.PutCString(
+            'error: logging is already in progress with file "%s"' % g_log_file
+        )
+    else:
+        args_len = len(args)
+        if args_len == 0:
+            g_log_file = tempfile.NamedTemporaryFile(delete=False).name
+        elif len(args) == 1:
+            g_log_file = args[0]
+
+        if g_log_file:
+            debugger.HandleCommand(
+                'log enable --threadsafe --timestamp --file "%s" gdb-remote packets'
+                % g_log_file
+            )
+            result.PutCString(
+                "GDB packet logging enable with log file '%s'\nUse the 'stop_gdb_log' command to stop logging and show packet statistics."
+                % g_log_file
+            )
+            return
+
+        result.PutCString("error: invalid log file path")
+    result.PutCString(usage)
+
+
+def stop_gdb_log(debugger, command, result, dict):
+    """Stop logging GDB remote packets to the file that was specified in a call
+    to "start_gdb_log" and normalize the timestamps to be relative to the first
+    timestamp in the log file. Also print out statistics for how long each
+    command took to allow performance bottlenecks to be determined."""
+    global g_log_file
+    # Any commands whose names might be followed by more valid C identifier
+    # characters must be listed here
+    command_args = shlex.split(command)
+    usage = "usage: stop_gdb_log [options]"
+    description = """The command stops a previously enabled GDB remote packet logging command. Packet logging must have been previously enabled with a call to start_gdb_log."""
+    parser = optparse.OptionParser(
+        description=description, prog="stop_gdb_log", usage=usage
+    )
+    parser.add_option(
+        "-v",
+        "--verbose",
+        action="store_true",
+        dest="verbose",
+        help="display verbose debug info",
+        default=False,
+    )
+    parser.add_option(
+        "--plot",
+        action="store_true",
+        dest="plot",
+        help="plot packet latencies by packet type",
+        default=False,
+    )
+    parser.add_option(
+        "-q",
+        "--quiet",
+        action="store_true",
+        dest="quiet",
+        help="display verbose debug info",
+        default=False,
+    )
+    parser.add_option(
+        "-C",
+        "--color",
+        action="store_true",
+        dest="color",
+        help="add terminal colors",
+        default=False,
+    )
+    parser.add_option(
+        "-c",
+        "--sort-by-count",
+        action="store_true",
+        dest="sort_count",
+        help="display verbose debug info",
+        default=False,
+    )
+    parser.add_option(
+        "-s",
+        "--symbolicate",
+        action="store_true",
+        dest="symbolicate",
+        help='symbolicate addresses in log using current "lldb.target"',
+        default=False,
+    )
+    try:
+        (options, args) = parser.parse_args(command_args)
+    except:
+        return
+    options.colors = TerminalColors(options.color)
+    options.symbolicator = None
+    if options.symbolicate:
+        if lldb.target:
+            import lldb.utils.symbolication
+
+            options.symbolicator = lldb.utils.symbolication.Symbolicator()
+            options.symbolicator.target = lldb.target
+        else:
+            print("error: can't symbolicate without a target")
+
+    if not g_log_file:
+        result.PutCString(
+            'error: logging must have been previously enabled with a call to "stop_gdb_log"'
+        )
+    elif os.path.exists(g_log_file):
+        if len(args) == 0:
+            debugger.HandleCommand("log disable gdb-remote packets")
+            result.PutCString(
+                "GDB packet logging disabled. Logged packets are in '%s'" % g_log_file
+            )
+            parse_gdb_log_file(g_log_file, options)
+        else:
+            result.PutCString(usage)
+    else:
+        print('error: the GDB packet log file "%s" does not exist' % g_log_file)
+
+
+def is_hex_byte(str):
+    if len(str) == 2:
+        return str[0] in string.hexdigits and str[1] in string.hexdigits
+    return False
+
+
+def get_hex_string_if_all_printable(str):
+    try:
+        s = binascii.unhexlify(str).decode()
+        if all(c in string.printable for c in s):
+            return s
+    except (TypeError, binascii.Error, UnicodeDecodeError):
+        pass
+    return None
+
+
+# global register info list
+g_register_infos = list()
+g_max_register_info_name_len = 0
+
+
+class RegisterInfo:
+    """Class that represents register information"""
+
+    def __init__(self, kvp):
+        self.info = dict()
+        for kv in kvp:
+            key = kv[0]
+            value = kv[1]
+            self.info[key] = value
+
+    def name(self):
+        """Get the name of the register."""
+        if self.info and "name" in self.info:
+            return self.info["name"]
+        return None
+
+    def bit_size(self):
+        """Get the size in bits of the register."""
+        if self.info and "bitsize" in self.info:
+            return int(self.info["bitsize"])
+        return 0
+
+    def byte_size(self):
+        """Get the size in bytes of the register."""
+        return self.bit_size() / 8
+
+    def get_value_from_hex_string(self, hex_str):
+        """Dump the register value given a native byte order encoded hex ASCII byte string."""
+        encoding = self.info["encoding"]
+        bit_size = self.bit_size()
+        packet = Packet(hex_str)
+        if encoding == "uint":
+            uval = packet.get_hex_uint(g_byte_order)
+            if bit_size == 8:
+                return "0x%2.2x" % (uval)
+            elif bit_size == 16:
+                return "0x%4.4x" % (uval)
+            elif bit_size == 32:
+                return "0x%8.8x" % (uval)
+            elif bit_size == 64:
+                return "0x%16.16x" % (uval)
+        bytes = list()
+        uval = packet.get_hex_uint8()
+        while uval is not None:
+            bytes.append(uval)
+            uval = packet.get_hex_uint8()
+        value_str = "0x"
+        if g_byte_order == "little":
+            bytes.reverse()
+        for byte in bytes:
+            value_str += "%2.2x" % byte
+        return "%s" % (value_str)
+
+    def __str__(self):
+        """Dump the register info key/value pairs"""
+        s = ""
+        for key in self.info.keys():
+            if s:
+                s += ", "
+            s += "%s=%s " % (key, self.info[key])
+        return s
+
+
+class Packet:
+    """Class that represents a packet that contains string data"""
+
+    def __init__(self, packet_str):
+        self.str = packet_str
+
+    def peek_char(self):
+        ch = 0
+        if self.str:
+            ch = self.str[0]
+        return ch
+
+    def get_char(self):
+        ch = 0
+        if self.str:
+            ch = self.str[0]
+            self.str = self.str[1:]
+        return ch
+
+    def skip_exact_string(self, s):
+        if self.str and self.str.startswith(s):
+            self.str = self.str[len(s) :]
+            return True
+        else:
+            return False
+
+    def get_thread_id(self, fail_value=-1):
+        match = g_number_regex.match(self.str)
+        if match:
+            number_str = match.group(1)
+            self.str = self.str[len(number_str) :]
+            return int(number_str, 0)
+        else:
+            return fail_value
+
+    def get_hex_uint8(self):
+        if (
+            self.str
+            and len(self.str) >= 2
+            and self.str[0] in string.hexdigits
+            and self.str[1] in string.hexdigits
+        ):
+            uval = int(self.str[0:2], 16)
+            self.str = self.str[2:]
+            return uval
+        return None
+
+    def get_hex_uint16(self, byte_order):
+        uval = 0
+        if byte_order == "big":
+            uval |= self.get_hex_uint8() << 8
+            uval |= self.get_hex_uint8()
+        else:
+            uval |= self.get_hex_uint8()
+            uval |= self.get_hex_uint8() << 8
+        return uval
+
+    def get_hex_uint32(self, byte_order):
+        uval = 0
+        if byte_order == "big":
+            uval |= self.get_hex_uint8() << 24
+            uval |= self.get_hex_uint8() << 16
+            uval |= self.get_hex_uint8() << 8
+            uval |= self.get_hex_uint8()
+        else:
+            uval |= self.get_hex_uint8()
+            uval |= self.get_hex_uint8() << 8
+            uval |= self.get_hex_uint8() << 16
+            uval |= self.get_hex_uint8() << 24
+        return uval
+
+    def get_hex_uint64(self, byte_order):
+        uval = 0
+        if byte_order == "big":
+            uval |= self.get_hex_uint8() << 56
+            uval |= self.get_hex_uint8() << 48
+            uval |= self.get_hex_uint8() << 40
+            uval |= self.get_hex_uint8() << 32
+            uval |= self.get_hex_uint8() << 24
+            uval |= self.get_hex_uint8() << 16
+            uval |= self.get_hex_uint8() << 8
+            uval |= self.get_hex_uint8()
+        else:
+            uval |= self.get_hex_uint8()
+            uval |= self.get_hex_uint8() << 8
+            uval |= self.get_hex_uint8() << 16
+            uval |= self.get_hex_uint8() << 24
+            uval |= self.get_hex_uint8() << 32
+            uval |= self.get_hex_uint8() << 40
+            uval |= self.get_hex_uint8() << 48
+            uval |= self.get_hex_uint8() << 56
+        return uval
+
+    def get_number(self, fail_value=-1):
+        """Get a number from the packet. The number must be in big endian format and should be parsed
+        according to its prefix (starts with "0x" means hex, starts with "0" means octal, starts with
+        [1-9] means decimal, etc)"""
+        match = g_number_regex.match(self.str)
+        if match:
+            number_str = match.group(1)
+            self.str = self.str[len(number_str) :]
+            return int(number_str, 0)
+        else:
+            return fail_value
+
+    def get_hex_ascii_str(self, n=0):
+        hex_chars = self.get_hex_chars(n)
+        if hex_chars:
+            return binascii.unhexlify(hex_chars)
+        else:
+            return None
+
+    def get_hex_chars(self, n=0):
+        str_len = len(self.str)
+        if n == 0:
+            # n was zero, so we need to determine all hex chars and
+            # stop when we hit the end of the string of a non-hex character
+            while n < str_len and self.str[n] in string.hexdigits:
+                n = n + 1
+        else:
+            if n > str_len:
+                return None  # Not enough chars
+            # Verify all chars are hex if a length was specified
+            for i in range(n):
+                if self.str[i] not in string.hexdigits:
+                    return None  # Not all hex digits
+        if n == 0:
+            return None
+        hex_str = self.str[0:n]
+        self.str = self.str[n:]
+        return hex_str
+
+    def get_hex_uint(self, byte_order, n=0):
+        if byte_order == "big":
+            hex_str = self.get_hex_chars(n)
+            if hex_str is None:
+                return None
+            return int(hex_str, 16)
+        else:
+            uval = self.get_hex_uint8()
+            if uval is None:
+                return None
+            uval_result = 0
+            shift = 0
+            while uval is not None:
+                uval_result |= uval << shift
+                shift += 8
+                uval = self.get_hex_uint8()
+            return uval_result
+
+    def get_key_value_pairs(self):
+        kvp = list()
+        if ";" in self.str:
+            key_value_pairs = self.str.split(";")
+            for key_value_pair in key_value_pairs:
+                if len(key_value_pair):
+                    kvp.append(key_value_pair.split(":", 1))
+        return kvp
+
+    def split(self, ch):
+        return self.str.split(ch)
+
+    def split_hex(self, ch, byte_order):
+        hex_values = list()
+        strings = self.str.split(ch)
+        for str in strings:
+            hex_values.append(Packet(str).get_hex_uint(byte_order))
+        return hex_values
+
+    def __str__(self):
+        return self.str
+
+    def __len__(self):
+        return len(self.str)
+
+
+g_thread_suffix_regex = re.compile(";thread:([0-9a-fA-F]+);")
+
+
+def get_thread_from_thread_suffix(str):
+    if str:
+        match = g_thread_suffix_regex.match(str)
+        if match:
+            return int(match.group(1), 16)
+    return None
+
+
+def cmd_qThreadStopInfo(options, cmd, args):
+    packet = Packet(args)
+    tid = packet.get_hex_uint("big")
+    print("get_thread_stop_info  (tid = 0x%x)" % (tid))
+
+
+def cmd_stop_reply(options, cmd, args):
+    print("get_last_stop_info()")
+    return False
+
+
+def rsp_stop_reply(options, cmd, cmd_args, rsp):
+    global g_byte_order
+    packet = Packet(rsp)
+    stop_type = packet.get_char()
+    if stop_type == "T" or stop_type == "S":
+        signo = packet.get_hex_uint8()
+        key_value_pairs = packet.get_key_value_pairs()
+        for key_value_pair in key_value_pairs:
+            key = key_value_pair[0]
+            if is_hex_byte(key):
+                reg_num = Packet(key).get_hex_uint8()
+                if reg_num < len(g_register_infos):
+                    reg_info = g_register_infos[reg_num]
+                    key_value_pair[0] = reg_info.name()
+                    key_value_pair[1] = reg_info.get_value_from_hex_string(
+                        key_value_pair[1]
+                    )
+            elif key == "jthreads" or key == "jstopinfo":
+                key_value_pair[1] = binascii.unhexlify(key_value_pair[1])
+        key_value_pairs.insert(0, ["signal", signo])
+        print("stop_reply():")
+        dump_key_value_pairs(key_value_pairs)
+    elif stop_type == "W":
+        exit_status = packet.get_hex_uint8()
+        print("stop_reply(): exit (status=%i)" % exit_status)
+    elif stop_type == "O":
+        print('stop_reply(): stdout = "%s"' % packet.str)
+
+
+def cmd_unknown_packet(options, cmd, args):
+    if args:
+        print("cmd: %s, args: %s", cmd, args)
+    else:
+        print("cmd: %s", cmd)
+    return False
+
+
+def cmd_qSymbol(options, cmd, args):
+    if args == ":":
+        print("ready to serve symbols")
+    else:
+        packet = Packet(args)
+        symbol_addr = packet.get_hex_uint("big")
+        if symbol_addr is None:
+            if packet.skip_exact_string(":"):
+                symbol_name = packet.get_hex_ascii_str()
+                print('lookup_symbol("%s") -> symbol not available yet' % (symbol_name))
+            else:
+                print("error: bad command format")
+        else:
+            if packet.skip_exact_string(":"):
+                symbol_name = packet.get_hex_ascii_str()
+                print('lookup_symbol("%s") -> 0x%x' % (symbol_name, symbol_addr))
+            else:
+                print("error: bad command format")
+
+
+def cmd_QSetWithHexString(options, cmd, args):
+    print('%s("%s")' % (cmd[:-1], binascii.unhexlify(args)))
+
+
+def cmd_QSetWithString(options, cmd, args):
+    print('%s("%s")' % (cmd[:-1], args))
+
+
+def cmd_QSetWithUnsigned(options, cmd, args):
+    print("%s(%i)" % (cmd[:-1], int(args)))
+
+
+def rsp_qSymbol(options, cmd, cmd_args, rsp):
+    if len(rsp) == 0:
+        print("Unsupported")
+    else:
+        if rsp == "OK":
+            print("No more symbols to lookup")
+        else:
+            packet = Packet(rsp)
+            if packet.skip_exact_string("qSymbol:"):
+                symbol_name = packet.get_hex_ascii_str()
+                print('lookup_symbol("%s")' % (symbol_name))
+            else:
+                print(
+                    'error: response string should start with "qSymbol:": respnse is "%s"'
+                    % (rsp)
+                )
+
+
+def cmd_qXfer(options, cmd, args):
+    # $qXfer:features:read:target.xml:0,1ffff#14
+    print("read target special data %s" % (args))
+    return True
+
+
+def rsp_qXfer(options, cmd, cmd_args, rsp):
+    data = cmd_args.split(":")
+    if data[0] == "features":
+        if data[1] == "read":
+            filename, extension = os.path.splitext(data[2])
+            if extension == ".xml":
+                response = Packet(rsp)
+                xml_string = response.get_hex_ascii_str()
+                if xml_string:
+                    ch = xml_string[0]
+                    if ch == "l":
+                        xml_string = xml_string[1:]
+                        xml_root = ET.fromstring(xml_string)
+                        for reg_element in xml_root.findall("./feature/reg"):
+                            if not "value_regnums" in reg_element.attrib:
+                                reg_info = RegisterInfo([])
+                                if "name" in reg_element.attrib:
+                                    reg_info.info["name"] = reg_element.attrib["name"]
+                                else:
+                                    reg_info.info["name"] = "unspecified"
+                                if "encoding" in reg_element.attrib:
+                                    reg_info.info["encoding"] = reg_element.attrib[
+                                        "encoding"
+                                    ]
+                                else:
+                                    reg_info.info["encoding"] = "uint"
+                                if "offset" in reg_element.attrib:
+                                    reg_info.info["offset"] = reg_element.attrib[
+                                        "offset"
+                                    ]
+                                if "bitsize" in reg_element.attrib:
+                                    reg_info.info["bitsize"] = reg_element.attrib[
+                                        "bitsize"
+                                    ]
+                                g_register_infos.append(reg_info)
+                        print('XML for "%s":' % (data[2]))
+                        ET.dump(xml_root)
+
+
+def cmd_A(options, cmd, args):
+    print("launch process:")
+    packet = Packet(args)
+    while True:
+        arg_len = packet.get_number()
+        if arg_len == -1:
+            break
+        if not packet.skip_exact_string(","):
+            break
+        arg_idx = packet.get_number()
+        if arg_idx == -1:
+            break
+        if not packet.skip_exact_string(","):
+            break
+        arg_value = packet.get_hex_ascii_str(arg_len)
+        print('argv[%u] = "%s"' % (arg_idx, arg_value))
+
+
+def cmd_qC(options, cmd, args):
+    print("query_current_thread_id()")
+
+
+def rsp_qC(options, cmd, cmd_args, rsp):
+    packet = Packet(rsp)
+    if packet.skip_exact_string("QC"):
+        tid = packet.get_thread_id()
+        print("current_thread_id = %#x" % (tid))
+    else:
+        print("current_thread_id = old thread ID")
+
+
+def cmd_query_packet(options, cmd, args):
+    if args:
+        print("%s%s" % (cmd, args))
+    else:
+        print("%s" % (cmd))
+    return False
+
+
+def rsp_ok_error(rsp):
+    print("rsp: ", rsp)
+
+
+def rsp_ok_means_supported(options, cmd, cmd_args, rsp):
+    if rsp == "OK":
+        print("%s%s is supported" % (cmd, cmd_args))
+    elif rsp == "":
+        print("%s%s is not supported" % (cmd, cmd_args))
+    else:
+        print("%s%s -> %s" % (cmd, cmd_args, rsp))
+
+
+def rsp_ok_means_success(options, cmd, cmd_args, rsp):
+    if rsp == "OK":
+        print("success")
+    elif rsp == "":
+        print("%s%s is not supported" % (cmd, cmd_args))
+    else:
+        print("%s%s -> %s" % (cmd, cmd_args, rsp))
+
+
+def dump_key_value_pairs(key_value_pairs):
+    max_key_len = 0
+    for key_value_pair in key_value_pairs:
+        key_len = len(key_value_pair[0])
+        if max_key_len < key_len:
+            max_key_len = key_len
+    for key_value_pair in key_value_pairs:
+        key = key_value_pair[0]
+        value = key_value_pair[1]
+        unhex_value = get_hex_string_if_all_printable(value)
+        if unhex_value:
+            print("%*s = %s (%s)" % (max_key_len, key, value, unhex_value))
+        else:
+            print("%*s = %s" % (max_key_len, key, value))
+
+
+def rsp_dump_key_value_pairs(options, cmd, cmd_args, rsp):
+    if rsp:
+        print("%s response:" % (cmd))
+        packet = Packet(rsp)
+        key_value_pairs = packet.get_key_value_pairs()
+        dump_key_value_pairs(key_value_pairs)
+    else:
+        print("not supported")
+
+
+def cmd_c(options, cmd, args):
+    print("continue()")
+    return False
+
+
+def cmd_s(options, cmd, args):
+    print("step()")
+    return False
+
+
+def cmd_qSpeedTest(options, cmd, args):
+    print(("qSpeedTest: cmd='%s', args='%s'" % (cmd, args)))
+
+
+def rsp_qSpeedTest(options, cmd, cmd_args, rsp):
+    print(("qSpeedTest: rsp='%s' cmd='%s', args='%s'" % (rsp, cmd, args)))
+
+
+def cmd_vCont(options, cmd, args):
+    if args == "?":
+        print("%s: get supported extended continue modes" % (cmd))
+    else:
+        got_other_threads = 0
+        s = ""
+        for thread_action in args[1:].split(";"):
+            (short_action, thread) = thread_action.split(":", 1)
+            tid = int(thread, 16)
+            if short_action == "c":
+                action = "continue"
+            elif short_action == "s":
+                action = "step"
+            elif short_action[0] == "C":
+                action = "continue with signal 0x%s" % (short_action[1:])
+            elif short_action == "S":
+                action = "step with signal 0x%s" % (short_action[1:])
+            else:
+                action = short_action
+            if s:
+                s += ", "
+            if tid == -1:
+                got_other_threads = 1
+                s += "other-threads:"
+            else:
+                s += "thread 0x%4.4x: %s" % (tid, action)
+        if got_other_threads:
+            print("extended_continue (%s)" % (s))
+        else:
+            print("extended_continue (%s, other-threads: suspend)" % (s))
+    return False
+
+
+def rsp_vCont(options, cmd, cmd_args, rsp):
+    if cmd_args == "?":
+        # Skip the leading 'vCont;'
+        rsp = rsp[6:]
+        modes = rsp.split(";")
+        s = "%s: supported extended continue modes include: " % (cmd)
+
+        for i, mode in enumerate(modes):
+            if i:
+                s += ", "
+            if mode == "c":
+                s += "continue"
+            elif mode == "C":
+                s += "continue with signal"
+            elif mode == "s":
+                s += "step"
+            elif mode == "S":
+                s += "step with signal"
+            elif mode == "t":
+                s += "stop"
+            # else:
+            #     s += 'unrecognized vCont mode: ', str(mode)
+        print(s)
+    elif rsp:
+        if rsp[0] == "T" or rsp[0] == "S" or rsp[0] == "W" or rsp[0] == "X":
+            rsp_stop_reply(options, cmd, cmd_args, rsp)
+            return
+        if rsp[0] == "O":
+            print("stdout: %s" % (rsp))
+            return
+    else:
+        print(
+            "not supported (cmd = '%s', args = '%s', rsp = '%s')" % (cmd, cmd_args, rsp)
+        )
+
+
+def cmd_vAttach(options, cmd, args):
+    (extra_command, args) = args.split(";")
+    if extra_command:
+        print("%s%s(%s)" % (cmd, extra_command, args))
+    else:
+        print("attach(pid = %u)" % int(args, 16))
+    return False
+
+
+def cmd_qRegisterInfo(options, cmd, args):
+    print("query_register_info(reg_num=%i)" % (int(args, 16)))
+    return False
+
+
+def rsp_qRegisterInfo(options, cmd, cmd_args, rsp):
+    global g_max_register_info_name_len
+    print("query_register_info(reg_num=%i):" % (int(cmd_args, 16)), end=" ")
+    if len(rsp) == 3 and rsp[0] == "E":
+        g_max_register_info_name_len = 0
+        for reg_info in g_register_infos:
+            name_len = len(reg_info.name())
+            if g_max_register_info_name_len < name_len:
+                g_max_register_info_name_len = name_len
+        print(" DONE")
+    else:
+        packet = Packet(rsp)
+        reg_info = RegisterInfo(packet.get_key_value_pairs())
+        g_register_infos.append(reg_info)
+        print(reg_info)
+    return False
+
+
+def cmd_qThreadInfo(options, cmd, args):
+    if cmd == "qfThreadInfo":
+        query_type = "first"
+    else:
+        query_type = "subsequent"
+    print("get_current_thread_list(type=%s)" % (query_type))
+    return False
+
+
+def rsp_qThreadInfo(options, cmd, cmd_args, rsp):
+    packet = Packet(rsp)
+    response_type = packet.get_char()
+    if response_type == "m":
+        tids = packet.split_hex(";", "big")
+        for i, tid in enumerate(tids):
+            if i:
+                print(",", end=" ")
+            print("0x%x" % (tid), end=" ")
+        print()
+    elif response_type == "l":
+        print("END")
+
+
+def rsp_hex_big_endian(options, cmd, cmd_args, rsp):
+    if rsp == "":
+        print("%s%s is not supported" % (cmd, cmd_args))
+    else:
+        packet = Packet(rsp)
+        uval = packet.get_hex_uint("big")
+        print("%s: 0x%x" % (cmd, uval))
+
+
+def cmd_read_mem_bin(options, cmd, args):
+    # x0x7fff5fc39200,0x200
+    packet = Packet(args)
+    addr = packet.get_hex_uint("big")
+    comma = packet.get_char()
+    size = packet.get_hex_uint("big")
+    print("binary_read_memory (addr = 0x%16.16x, size = %u)" % (addr, size))
+    return False
+
+
+def rsp_mem_bin_bytes(options, cmd, cmd_args, rsp):
+    packet = Packet(cmd_args)
+    addr = packet.get_hex_uint("big")
+    comma = packet.get_char()
+    size = packet.get_hex_uint("big")
+    print("memory:")
+    if size > 0:
+        dump_hex_memory_buffer(addr, rsp)
+
+
+def cmd_read_memory(options, cmd, args):
+    packet = Packet(args)
+    addr = packet.get_hex_uint("big")
+    comma = packet.get_char()
+    size = packet.get_hex_uint("big")
+    print("read_memory (addr = 0x%16.16x, size = %u)" % (addr, size))
+    return False
+
+
+def dump_hex_memory_buffer(addr, hex_byte_str):
+    packet = Packet(hex_byte_str)
+    idx = 0
+    ascii = ""
+    uval = packet.get_hex_uint8()
+    while uval is not None:
+        if (idx % 16) == 0:
+            if ascii:
+                print("  ", ascii)
+                ascii = ""
+            print("0x%x:" % (addr + idx), end=" ")
+        print("%2.2x" % (uval), end=" ")
+        if 0x20 <= uval and uval < 0x7F:
+            ascii += "%c" % uval
+        else:
+            ascii += "."
+        uval = packet.get_hex_uint8()
+        idx = idx + 1
+    if ascii:
+        print("  ", ascii)
+        ascii = ""
+
+
+def cmd_write_memory(options, cmd, args):
+    packet = Packet(args)
+    addr = packet.get_hex_uint("big")
+    if packet.get_char() != ",":
+        print("error: invalid write memory command (missing comma after address)")
+        return
+    size = packet.get_hex_uint("big")
+    if packet.get_char() != ":":
+        print("error: invalid write memory command (missing colon after size)")
+        return
+    print("write_memory (addr = 0x%16.16x, size = %u, data:" % (addr, size))
+    dump_hex_memory_buffer(addr, packet.str)
+    return False
+
+
+def cmd_alloc_memory(options, cmd, args):
+    packet = Packet(args)
+    byte_size = packet.get_hex_uint("big")
+    if packet.get_char() != ",":
+        print("error: invalid allocate memory command (missing comma after address)")
+        return
+    print(
+        "allocate_memory (byte-size = %u (0x%x), permissions = %s)"
+        % (byte_size, byte_size, packet.str)
+    )
+    return False
+
+
+def rsp_alloc_memory(options, cmd, cmd_args, rsp):
+    packet = Packet(rsp)
+    addr = packet.get_hex_uint("big")
+    print("addr = 0x%x" % addr)
+
+
+def cmd_dealloc_memory(options, cmd, args):
+    packet = Packet(args)
+    addr = packet.get_hex_uint("big")
+    if packet.get_char() != ",":
+        print("error: invalid allocate memory command (missing comma after address)")
+    else:
+        print("deallocate_memory (addr = 0x%x, permissions = %s)" % (addr, packet.str))
+    return False
+
+
+def rsp_memory_bytes(options, cmd, cmd_args, rsp):
+    addr = Packet(cmd_args).get_hex_uint("big")
+    dump_hex_memory_buffer(addr, rsp)
+
+
+def get_register_name_equal_value(options, reg_num, hex_value_str):
+    if reg_num < len(g_register_infos):
+        reg_info = g_register_infos[reg_num]
+        value_str = reg_info.get_value_from_hex_string(hex_value_str)
+        s = reg_info.name() + " = "
+        if options.symbolicator:
+            symbolicated_addresses = options.symbolicator.symbolicate(int(value_str, 0))
+            if symbolicated_addresses:
+                s += options.colors.magenta()
+                s += "%s" % symbolicated_addresses[0]
+                s += options.colors.reset()
+                return s
+        s += value_str
+        return s
+    else:
+        reg_value = Packet(hex_value_str).get_hex_uint(g_byte_order)
+        return "reg(%u) = 0x%x" % (reg_num, reg_value)
+
+
+def cmd_read_one_reg(options, cmd, args):
+    packet = Packet(args)
+    reg_num = packet.get_hex_uint("big")
+    tid = get_thread_from_thread_suffix(packet.str)
+    name = None
+    if reg_num < len(g_register_infos):
+        name = g_register_infos[reg_num].name()
+    if packet.str:
+        packet.get_char()  # skip ;
+        thread_info = packet.get_key_value_pairs()
+        tid = int(thread_info[0][1], 16)
+    s = "read_register (reg_num=%u" % reg_num
+    if name:
+        s += " (%s)" % (name)
+    if tid is not None:
+        s += ", tid = 0x%4.4x" % (tid)
+    s += ")"
+    print(s)
+    return False
+
+
+def rsp_read_one_reg(options, cmd, cmd_args, rsp):
+    packet = Packet(cmd_args)
+    reg_num = packet.get_hex_uint("big")
+    print(get_register_name_equal_value(options, reg_num, rsp))
+
+
+def cmd_write_one_reg(options, cmd, args):
+    packet = Packet(args)
+    reg_num = packet.get_hex_uint("big")
+    if packet.get_char() != "=":
+        print("error: invalid register write packet")
+    else:
+        name = None
+        hex_value_str = packet.get_hex_chars()
+        tid = get_thread_from_thread_suffix(packet.str)
+        s = "write_register (reg_num=%u" % reg_num
+        if name:
+            s += " (%s)" % (name)
+        s += ", value = "
+        s += get_register_name_equal_value(options, reg_num, hex_value_str)
+        if tid is not None:
+            s += ", tid = 0x%4.4x" % (tid)
+        s += ")"
+        print(s)
+    return False
+
+
+def dump_all_regs(packet):
+    for reg_info in g_register_infos:
+        nibble_size = reg_info.bit_size() / 4
+        hex_value_str = packet.get_hex_chars(nibble_size)
+        if hex_value_str is not None:
+            value = reg_info.get_value_from_hex_string(hex_value_str)
+            print("%*s = %s" % (g_max_register_info_name_len, reg_info.name(), value))
+        else:
+            return
+
+
+def cmd_read_all_regs(cmd, cmd_args):
+    packet = Packet(cmd_args)
+    packet.get_char()  # toss the 'g' command character
+    tid = get_thread_from_thread_suffix(packet.str)
+    if tid is not None:
+        print("read_all_register(thread = 0x%4.4x)" % tid)
+    else:
+        print("read_all_register()")
+    return False
+
+
+def rsp_read_all_regs(options, cmd, cmd_args, rsp):
+    packet = Packet(rsp)
+    dump_all_regs(packet)
+
+
+def cmd_write_all_regs(options, cmd, args):
+    packet = Packet(args)
+    print("write_all_registers()")
+    dump_all_regs(packet)
+    return False
+
+
+g_bp_types = ["software_bp", "hardware_bp", "write_wp", "read_wp", "access_wp"]
+
+
+def cmd_bp(options, cmd, args):
+    if cmd == "Z":
+        s = "set_"
+    else:
+        s = "clear_"
+    packet = Packet(args)
+    bp_type = packet.get_hex_uint("big")
+    packet.get_char()  # Skip ,
+    bp_addr = packet.get_hex_uint("big")
+    packet.get_char()  # Skip ,
+    bp_size = packet.get_hex_uint("big")
+    s += g_bp_types[bp_type]
+    s += " (addr = 0x%x, size = %u)" % (bp_addr, bp_size)
+    print(s)
+    return False
+
+
+def cmd_mem_rgn_info(options, cmd, args):
+    packet = Packet(args)
+    packet.get_char()  # skip ':' character
+    addr = packet.get_hex_uint("big")
+    print("get_memory_region_info (addr=0x%x)" % (addr))
+    return False
+
+
+def cmd_kill(options, cmd, args):
+    print("kill_process()")
+    return False
+
+
+def cmd_jThreadsInfo(options, cmd, args):
+    print("jThreadsInfo()")
+    return False
+
+
+def cmd_jGetLoadedDynamicLibrariesInfos(options, cmd, args):
+    print("jGetLoadedDynamicLibrariesInfos()")
+    return False
+
+
+def decode_packet(s, start_index=0):
+    # print '\ndecode_packet("%s")' % (s[start_index:])
+    index = s.find("}", start_index)
+    have_escapes = index != -1
+    if have_escapes:
+        normal_s = s[start_index:index]
+    else:
+        normal_s = s[start_index:]
+    # print 'normal_s = "%s"' % (normal_s)
+    if have_escapes:
+        escape_char = "%c" % (ord(s[index + 1]) ^ 0x20)
+        # print 'escape_char for "%s" = %c' % (s[index:index+2], escape_char)
+        return normal_s + escape_char + decode_packet(s, index + 2)
+    else:
+        return normal_s
+
+
+def rsp_json(options, cmd, cmd_args, rsp):
+    print("%s() reply:" % (cmd))
+    if not rsp:
+        return
+    try:
+        json_tree = json.loads(rsp)
+        print(json.dumps(json_tree, indent=4, separators=(",", ": ")))
+    except json.JSONDecodeError:
+        return
+
+
+def rsp_jGetLoadedDynamicLibrariesInfos(options, cmd, cmd_args, rsp):
+    if cmd_args:
+        rsp_json(options, cmd, cmd_args, rsp)
+    else:
+        rsp_ok_means_supported(options, cmd, cmd_args, rsp)
+
+
+gdb_remote_commands = {
+    "\\?": {"cmd": cmd_stop_reply, "rsp": rsp_stop_reply, "name": "stop reply pacpket"},
+    "qThreadStopInfo": {
+        "cmd": cmd_qThreadStopInfo,
+        "rsp": rsp_stop_reply,
+        "name": "stop reply pacpket",
+    },
+    "QStartNoAckMode": {
+        "cmd": cmd_query_packet,
+        "rsp": rsp_ok_means_supported,
+        "name": "query if no ack mode is supported",
+    },
+    "QThreadSuffixSupported": {
+        "cmd": cmd_query_packet,
+        "rsp": rsp_ok_means_supported,
+        "name": "query if thread suffix is supported",
+    },
+    "QListThreadsInStopReply": {
+        "cmd": cmd_query_packet,
+        "rsp": rsp_ok_means_supported,
+        "name": "query if threads in stop reply packets are supported",
+    },
+    "QSetDetachOnError:": {
+        "cmd": cmd_QSetWithUnsigned,
+        "rsp": rsp_ok_means_success,
+        "name": "set if we should detach on error",
+    },
+    "QSetDisableASLR:": {
+        "cmd": cmd_QSetWithUnsigned,
+        "rsp": rsp_ok_means_success,
+        "name": "set if we should disable ASLR",
+    },
+    "qLaunchSuccess": {
+        "cmd": cmd_query_packet,
+        "rsp": rsp_ok_means_success,
+        "name": "check on launch success for the A packet",
+    },
+    "A": {"cmd": cmd_A, "rsp": rsp_ok_means_success, "name": "launch process"},
+    "QLaunchArch:": {
+        "cmd": cmd_QSetWithString,
+        "rsp": rsp_ok_means_supported,
+        "name": "set the arch to launch in case the file contains multiple architectures",
+    },
+    "qVAttachOrWaitSupported": {
+        "cmd": cmd_query_packet,
+        "rsp": rsp_ok_means_supported,
+        "name": "set the launch architecture",
+    },
+    "qHostInfo": {
+        "cmd": cmd_query_packet,
+        "rsp": rsp_dump_key_value_pairs,
+        "name": "get host information",
+    },
+    "qC": {"cmd": cmd_qC, "rsp": rsp_qC, "name": "return the current thread ID"},
+    "vCont": {"cmd": cmd_vCont, "rsp": rsp_vCont, "name": "extended continue command"},
+    "qSpeedTest": {
+        "cmd": cmd_qSpeedTest,
+        "rsp": rsp_qSpeedTest,
+        "name": "speed test packdet",
+    },
+    "vAttach": {"cmd": cmd_vAttach, "rsp": rsp_stop_reply, "name": "attach to process"},
+    "c": {"cmd": cmd_c, "rsp": rsp_stop_reply, "name": "continue"},
+    "s": {"cmd": cmd_s, "rsp": rsp_stop_reply, "name": "step"},
+    "qRegisterInfo": {
+        "cmd": cmd_qRegisterInfo,
+        "rsp": rsp_qRegisterInfo,
+        "name": "query register info",
+    },
+    "qfThreadInfo": {
+        "cmd": cmd_qThreadInfo,
+        "rsp": rsp_qThreadInfo,
+        "name": "get current thread list",
+    },
+    "qsThreadInfo": {
+        "cmd": cmd_qThreadInfo,
+        "rsp": rsp_qThreadInfo,
+        "name": "get current thread list",
+    },
+    "qShlibInfoAddr": {
+        "cmd": cmd_query_packet,
+        "rsp": rsp_hex_big_endian,
+        "name": "get shared library info address",
+    },
+    "qMemoryRegionInfo": {
+        "cmd": cmd_mem_rgn_info,
+        "rsp": rsp_dump_key_value_pairs,
+        "name": "get memory region information",
+    },
+    "qProcessInfo": {
+        "cmd": cmd_query_packet,
+        "rsp": rsp_dump_key_value_pairs,
+        "name": "get process info",
+    },
+    "qSupported": {
+        "cmd": cmd_query_packet,
+        "rsp": rsp_ok_means_supported,
+        "name": "query supported",
+    },
+    "qXfer:": {"cmd": cmd_qXfer, "rsp": rsp_qXfer, "name": "qXfer"},
+    "qSymbol:": {"cmd": cmd_qSymbol, "rsp": rsp_qSymbol, "name": "qSymbol"},
+    "QSetSTDIN:": {
+        "cmd": cmd_QSetWithHexString,
+        "rsp": rsp_ok_means_success,
+        "name": "set STDIN prior to launching with A packet",
+    },
+    "QSetSTDOUT:": {
+        "cmd": cmd_QSetWithHexString,
+        "rsp": rsp_ok_means_success,
+        "name": "set STDOUT prior to launching with A packet",
+    },
+    "QSetSTDERR:": {
+        "cmd": cmd_QSetWithHexString,
+        "rsp": rsp_ok_means_success,
+        "name": "set STDERR prior to launching with A packet",
+    },
+    "QEnvironment:": {
+        "cmd": cmd_QSetWithString,
+        "rsp": rsp_ok_means_success,
+        "name": "set an environment variable prior to launching with A packet",
+    },
+    "QEnvironmentHexEncoded:": {
+        "cmd": cmd_QSetWithHexString,
+        "rsp": rsp_ok_means_success,
+        "name": "set an environment variable prior to launching with A packet",
+    },
+    "x": {
+        "cmd": cmd_read_mem_bin,
+        "rsp": rsp_mem_bin_bytes,
+        "name": "read memory binary",
+    },
+    "X": {
+        "cmd": cmd_write_memory,
+        "rsp": rsp_ok_means_success,
+        "name": "write memory binary",
+    },
+    "m": {"cmd": cmd_read_memory, "rsp": rsp_memory_bytes, "name": "read memory"},
+    "M": {"cmd": cmd_write_memory, "rsp": rsp_ok_means_success, "name": "write memory"},
+    "_M": {"cmd": cmd_alloc_memory, "rsp": rsp_alloc_memory, "name": "allocate memory"},
+    "_m": {
+        "cmd": cmd_dealloc_memory,
+        "rsp": rsp_ok_means_success,
+        "name": "deallocate memory",
+    },
+    "p": {
+        "cmd": cmd_read_one_reg,
+        "rsp": rsp_read_one_reg,
+        "name": "read single register",
+    },
+    "P": {
+        "cmd": cmd_write_one_reg,
+        "rsp": rsp_ok_means_success,
+        "name": "write single register",
+    },
+    "g": {
+        "cmd": cmd_read_all_regs,
+        "rsp": rsp_read_all_regs,
+        "name": "read all registers",
+    },
+    "G": {
+        "cmd": cmd_write_all_regs,
+        "rsp": rsp_ok_means_success,
+        "name": "write all registers",
+    },
+    "z": {
+        "cmd": cmd_bp,
+        "rsp": rsp_ok_means_success,
+        "name": "clear breakpoint or watchpoint",
+    },
+    "Z": {
+        "cmd": cmd_bp,
+        "rsp": rsp_ok_means_success,
+        "name": "set breakpoint or watchpoint",
+    },
+    "k": {"cmd": cmd_kill, "rsp": rsp_stop_reply, "name": "kill process"},
+    "jThreadsInfo": {
+        "cmd": cmd_jThreadsInfo,
+        "rsp": rsp_json,
+        "name": "JSON get all threads info",
+    },
+    "jGetLoadedDynamicLibrariesInfos:": {
+        "cmd": cmd_jGetLoadedDynamicLibrariesInfos,
+        "rsp": rsp_jGetLoadedDynamicLibrariesInfos,
+        "name": "JSON get loaded dynamic libraries",
+    },
+}
+
+
+def calculate_mean_and_standard_deviation(floats):
+    sum = 0.0
+    count = len(floats)
+    if count == 0:
+        return (0.0, 0.0)
+    for f in floats:
+        sum += f
+    mean = sum / count
+    accum = 0.0
+    for f in floats:
+        delta = f - mean
+        accum += delta * delta
+
+    std_dev = math.sqrt(accum / (count - 1))
+    return (mean, std_dev)
+
+
+def parse_gdb_log_file(path, options):
+    f = open(path)
+    parse_gdb_log(f, options)
+    f.close()
+
+
+def round_up(n, incr):
+    return float(((int(n) + incr) / incr) * incr)
+
+
+def plot_latencies(sec_times):
+    # import numpy as np
+    import matplotlib.pyplot as plt
+
+    for i, name in enumerate(sec_times.keys()):
+        times = sec_times[name]
+        if len(times) <= 1:
+            continue
+        plt.subplot(2, 1, 1)
+        plt.title('Packet "%s" Times' % (name))
+        plt.xlabel("Packet")
+        units = "ms"
+        adj_times = []
+        max_time = 0.0
+        for time in times:
+            time = time * 1000.0
+            adj_times.append(time)
+            if time > max_time:
+                max_time = time
+        if max_time < 1.0:
+            units = "us"
+            max_time = 0.0
+            for i in range(len(adj_times)):
+                adj_times[i] *= 1000.0
+                if adj_times[i] > max_time:
+                    max_time = adj_times[i]
+        plt.ylabel("Time (%s)" % (units))
+        max_y = None
+        for i in [5.0, 10.0, 25.0, 50.0]:
+            if max_time < i:
+                max_y = round_up(max_time, i)
+                break
+        if max_y is None:
+            max_y = round_up(max_time, 100.0)
+        plt.ylim(0.0, max_y)
+        plt.plot(adj_times, "o-")
+        plt.show()
+
+
+def parse_gdb_log(file, options):
+    """Parse a GDB log file that was generated by enabling logging with:
+    (lldb) log enable --threadsafe --timestamp --file <FILE> gdb-remote packets
+    This log file will contain timestamps and this function will then normalize
+    those packets to be relative to the first value timestamp that is found and
+    show delta times between log lines and also keep track of how long it takes
+    for GDB remote commands to make a send/receive round trip. This can be
+    handy when trying to figure out why some operation in the debugger is taking
+    a long time during a preset set of debugger commands."""
+
+    tricky_commands = ["qRegisterInfo"]
+    timestamp_regex = re.compile(r"(\s*)([1-9][0-9]+\.[0-9]+)([^0-9].*)$")
+    packet_name_regex = re.compile("([A-Za-z_]+)[^a-z]")
+    packet_transmit_name_regex = re.compile(
+        "(?P<direction>send|read) packet: (?P<packet>.*)"
+    )
+    packet_contents_name_regex = re.compile(r"\$([^#]*)#[0-9a-fA-F]{2}")
+    packet_checksum_regex = re.compile(".*#[0-9a-fA-F]{2}$")
+    packet_names_regex_str = "(" + "|".join(gdb_remote_commands.keys()) + ")(.*)"
+    packet_names_regex = re.compile(packet_names_regex_str)
+
+    base_time = 0.0
+    last_time = 0.0
+    min_time = 100000000.0
+    packet_total_times = {}
+    all_packet_times = []
+    packet_times = {}
+    packet_counts = {}
+    lines = file.read().splitlines()
+    last_command = None
+    last_command_args = None
+    last_command_packet = None
+    hide_next_response = False
+    num_lines = len(lines)
+    skip_count = 0
+    for line_index, line in enumerate(lines):
+        # See if we need to skip any lines
+        if skip_count > 0:
+            skip_count -= 1
+            continue
+        m = packet_transmit_name_regex.search(line)
+        is_command = False
+        direction = None
+        if m:
+            direction = m.group("direction")
+            is_command = direction == "send"
+            packet = m.group("packet")
+            sys.stdout.write(options.colors.green())
+            if not options.quiet and not hide_next_response:
+                print("#  ", line)
+            sys.stdout.write(options.colors.reset())
+
+            # print 'direction = "%s", packet = "%s"' % (direction, packet)
+
+            if packet[0] == "+":
+                if is_command:
+                    print("-->", end=" ")
+                else:
+                    print("<--", end=" ")
+                if not options.quiet:
+                    print("ACK")
+                continue
+            elif packet[0] == "-":
+                if is_command:
+                    print("-->", end=" ")
+                else:
+                    print("<--", end=" ")
+                if not options.quiet:
+                    print("NACK")
+                continue
+            elif packet[0] == "$":
+                m = packet_contents_name_regex.match(packet)
+                if not m and packet[0] == "$":
+                    multiline_packet = packet
+                    idx = line_index + 1
+                    while idx < num_lines:
+                        if not options.quiet and not hide_next_response:
+                            print("#  ", lines[idx])
+                        multiline_packet += lines[idx]
+                        m = packet_contents_name_regex.match(multiline_packet)
+                        if m:
+                            packet = multiline_packet
+                            skip_count = idx - line_index
+                            break
+                        else:
+                            idx += 1
+                if m:
+                    if is_command:
+                        print("-->", end=" ")
+                    else:
+                        print("<--", end=" ")
+                    contents = decode_packet(m.group(1))
+                    if is_command:
+                        hide_next_response = False
+                        m = packet_names_regex.match(contents)
+                        if m:
+                            last_command = m.group(1)
+                            if last_command == "?":
+                                last_command = "\\?"
+                            packet_name = last_command
+                            last_command_args = m.group(2)
+                            last_command_packet = contents
+                            hide_next_response = gdb_remote_commands[last_command][
+                                "cmd"
+                            ](options, last_command, last_command_args)
+                        else:
+                            packet_match = packet_name_regex.match(contents)
+                            if packet_match:
+                                packet_name = packet_match.group(1)
+                                for tricky_cmd in tricky_commands:
+                                    if packet_name.find(tricky_cmd) == 0:
+                                        packet_name = tricky_cmd
+                            else:
+                                packet_name = contents
+                            last_command = None
+                            last_command_args = None
+                            last_command_packet = None
+                    elif last_command:
+                        gdb_remote_commands[last_command]["rsp"](
+                            options, last_command, last_command_args, contents
+                        )
+                else:
+                    print('error: invalid packet: "', packet, '"')
+            else:
+                print("???")
+        else:
+            print("## ", line)
+        match = timestamp_regex.match(line)
+        if match:
+            curr_time = float(match.group(2))
+            if last_time and not is_command:
+                delta = curr_time - last_time
+                all_packet_times.append(delta)
+            delta = 0.0
+            if base_time:
+                delta = curr_time - last_time
+            else:
+                base_time = curr_time
+
+            if not is_command:
+                if line.find("read packet: $") >= 0 and packet_name:
+                    if packet_name in packet_total_times:
+                        packet_total_times[packet_name] += delta
+                        packet_counts[packet_name] += 1
+                    else:
+                        packet_total_times[packet_name] = delta
+                        packet_counts[packet_name] = 1
+                    if packet_name not in packet_times:
+                        packet_times[packet_name] = []
+                    packet_times[packet_name].append(delta)
+                    packet_name = None
+                if min_time > delta:
+                    min_time = delta
+
+            if not options or not options.quiet:
+                print(
+                    "%s%.6f %+.6f%s"
+                    % (match.group(1), curr_time - base_time, delta, match.group(3))
+                )
+            last_time = curr_time
+        # else:
+        #     print line
+    (average, std_dev) = calculate_mean_and_standard_deviation(all_packet_times)
+    if average and std_dev:
+        print(
+            "%u packets with average packet time of %f and standard deviation of %f"
+            % (len(all_packet_times), average, std_dev)
+        )
+    if packet_total_times:
+        total_packet_time = 0.0
+        total_packet_count = 0
+        for key, vvv in packet_total_times.items():
+            # print '  key = (%s) "%s"' % (type(key), key)
+            # print 'value = (%s) %s' % (type(vvv), vvv)
+            # if type(vvv) == 'float':
+            total_packet_time += vvv
+        for key, vvv in packet_counts.items():
+            total_packet_count += vvv
+
+        print("#------------------------------------------------------------")
+        print("# Packet timing summary:")
+        print(
+            "# Totals: time = %6f, count = %6d"
+            % (total_packet_time, total_packet_count)
+        )
+        print("# Min packet time: time = %6f" % (min_time))
+        print("#------------------------------------------------------------")
+        print("# Packet                   Time (sec)  Percent Count  Latency")
+        print("#------------------------- ----------- ------- ------ -------")
+        if options and options.sort_count:
+            res = sorted(packet_counts, key=packet_counts.__getitem__, reverse=True)
+        else:
+            res = sorted(
+                packet_total_times, key=packet_total_times.__getitem__, reverse=True
+            )
+
+        if last_time > 0.0:
+            for item in res:
+                packet_total_time = packet_total_times[item]
+                packet_percent = (packet_total_time / total_packet_time) * 100.0
+                packet_count = packet_counts[item]
+                print(
+                    "  %24s %11.6f  %5.2f%% %6d %9.6f"
+                    % (
+                        item,
+                        packet_total_time,
+                        packet_percent,
+                        packet_count,
+                        float(packet_total_time) / float(packet_count),
+                    )
+                )
+        if options and options.plot:
+            plot_latencies(packet_times)
+
+
+if __name__ == "__main__":
+    usage = "usage: gdbremote [options]"
+    description = """The command disassembles a GDB remote packet log."""
+    parser = optparse.OptionParser(
+        description=description, prog="gdbremote", usage=usage
+    )
+    parser.add_option(
+        "-v",
+        "--verbose",
+        action="store_true",
+        dest="verbose",
+        help="display verbose debug info",
+        default=False,
+    )
+    parser.add_option(
+        "-q",
+        "--quiet",
+        action="store_true",
+        dest="quiet",
+        help="display verbose debug info",
+        default=False,
+    )
+    parser.add_option(
+        "-C",
+        "--color",
+        action="store_true",
+        dest="color",
+        help="add terminal colors",
+        default=False,
+    )
+    parser.add_option(
+        "-c",
+        "--sort-by-count",
+        action="store_true",
+        dest="sort_count",
+        help="display verbose debug info",
+        default=False,
+    )
+    parser.add_option(
+        "--crashlog",
+        type="string",
+        dest="crashlog",
+        help="symbolicate using a darwin crash log file",
+        default=False,
+    )
+    try:
+        (options, args) = parser.parse_args(sys.argv[1:])
+    except:
+        print("error: argument error")
+        sys.exit(1)
+
+    options.colors = TerminalColors(options.color)
+    options.symbolicator = None
+    if options.crashlog:
+        import lldb
+
+        lldb.debugger = lldb.SBDebugger.Create()
+        import lldb.macosx.crashlog
+
+        options.symbolicator = lldb.macosx.crashlog.CrashLog(options.crashlog)
+        print("%s" % (options.symbolicator))
+
+    # This script is being run from the command line, create a debugger in case we are
+    # going to use any debugger functions in our function.
+    if len(args):
+        for file in args:
+            print(
+                "#----------------------------------------------------------------------"
+            )
+            print("# GDB remote log file: '%s'" % file)
+            print(
+                "#----------------------------------------------------------------------"
+            )
+            parse_gdb_log_file(file, options)
+        if options.symbolicator:
+            print("%s" % (options.symbolicator))
+    else:
+        parse_gdb_log(sys.stdin, options)
+
+
+def __lldb_init_module(debugger, internal_dict):
+    # This initializer is being run from LLDB in the embedded command interpreter
+    # Add any commands contained in this module to LLDB
+    debugger.HandleCommand(
+        "command script add -o -f gdbremote.start_gdb_log start_gdb_log"
+    )
+    debugger.HandleCommand(
+        "command script add -o -f gdbremote.stop_gdb_log stop_gdb_log"
+    )
+    print(
+        'The "start_gdb_log" and "stop_gdb_log" commands are now installed and ready for use, type "start_gdb_log --help" or "stop_gdb_log --help" for more information'
+    )



More information about the cfe-commits mailing list