[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