|
|
<!DOCTYPE html>
|
|
|
<html lang="zh-cn" dir="ltr">
|
|
|
<head>
|
|
|
<meta charset="UTF-8">
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
<meta name="description" content="Delve # Delve1 是使用Go语言实现的,专门用来调试Go程序的工具。它跟 GDB 工具类似,相比 GDB,它简单易用,能更好的理解Go语言数据结构和语言特性。它支持打印 goroutine 以及 defer 函数等Go特有语法特性。Delve 简称 dlv,后文将以 dlv 代称 Delve.
|
|
|
安装 # go get -u github.com/go-delve/delve/cmd/dlv 使用 # 开始调试 # dlv 使用 debug 命令进入调试界面:
|
|
|
dlv debug main.go 如果当前目录是 main 包所在目录时候,可以不用指定 main.go 文件这个参数的。假定项目结构如下:
|
|
|
. ├── github.com/me/foo ├── cmd │ └── foo │ └── main.go ├── pkg │ └── baz │ ├── bar.go │ └── bar_test.go 如果当前已在 cmd/foo 目录下,我们可以直接执行 dlv debug 命令开始调试。在任何目录下我们可以使用 dlv debug github.com/me/foo/cmd/foo 开始调试。">
|
|
|
<meta name="theme-color" media="(prefers-color-scheme: light)" content="#ffffff">
|
|
|
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="#343a40">
|
|
|
<meta name="color-scheme" content="light dark"><meta property="og:title" content="Delve is a debugger for the Go programming language" />
|
|
|
<meta property="og:description" content="Delve # Delve1 是使用Go语言实现的,专门用来调试Go程序的工具。它跟 GDB 工具类似,相比 GDB,它简单易用,能更好的理解Go语言数据结构和语言特性。它支持打印 goroutine 以及 defer 函数等Go特有语法特性。Delve 简称 dlv,后文将以 dlv 代称 Delve.
|
|
|
安装 # go get -u github.com/go-delve/delve/cmd/dlv 使用 # 开始调试 # dlv 使用 debug 命令进入调试界面:
|
|
|
dlv debug main.go 如果当前目录是 main 包所在目录时候,可以不用指定 main.go 文件这个参数的。假定项目结构如下:
|
|
|
. ├── github.com/me/foo ├── cmd │ └── foo │ └── main.go ├── pkg │ └── baz │ ├── bar.go │ └── bar_test.go 如果当前已在 cmd/foo 目录下,我们可以直接执行 dlv debug 命令开始调试。在任何目录下我们可以使用 dlv debug github.com/me/foo/cmd/foo 开始调试。" />
|
|
|
<meta property="og:type" content="article" />
|
|
|
<meta property="og:url" content="https://go.cyub.vip/analysis-tools/dlv/" /><meta property="article:section" content="analysis-tools" />
|
|
|
|
|
|
|
|
|
<title>Delve is a debugger for the Go programming language | 深入Go语言之旅</title>
|
|
|
<link rel="manifest" href="/manifest.json">
|
|
|
<link rel="icon" href="/favicon.png" >
|
|
|
<link rel="stylesheet" href="/book.min.f06572240ce28e67eb332ac5cf5d59a696c47ad4c6f700d5842c5ed93dd8ec77.css" integrity="sha256-8GVyJAzijmfrMyrFz11ZppbEetTG9wDVhCxe2T3Y7Hc=" crossorigin="anonymous">
|
|
|
<script defer src="/flexsearch.min.js"></script>
|
|
|
<script defer src="/en.search.min.93e09a692e83129c8b0cc95c521eab7d4f5256b35651cf852c4ad4185bdc55a5.js" integrity="sha256-k+CaaS6DEpyLDMlcUh6rfU9SVrNWUc+FLErUGFvcVaU=" crossorigin="anonymous"></script>
|
|
|
|
|
|
<script async src="https://www.googletagmanager.com/gtag/js?id=G-BQ229RRTTX"></script>
|
|
|
<script>
|
|
|
var doNotTrack = false;
|
|
|
if (!doNotTrack) {
|
|
|
window.dataLayer = window.dataLayer || [];
|
|
|
function gtag(){dataLayer.push(arguments);}
|
|
|
gtag('js', new Date());
|
|
|
gtag('config', 'G-BQ229RRTTX', { 'anonymize_ip': false });
|
|
|
}
|
|
|
</script>
|
|
|
<!--
|
|
|
Made with Book Theme
|
|
|
https://github.com/alex-shpak/hugo-book
|
|
|
-->
|
|
|
|
|
|
</head>
|
|
|
<body dir="ltr">
|
|
|
<input type="checkbox" class="hidden toggle" id="menu-control" />
|
|
|
<input type="checkbox" class="hidden toggle" id="toc-control" />
|
|
|
<main class="container flex">
|
|
|
<aside class="book-menu">
|
|
|
<div class="book-menu-content">
|
|
|
|
|
|
<nav>
|
|
|
<h2 class="book-brand">
|
|
|
<a class="flex align-center" href="/"><img src="https://static.cyub.vip/images/202310/golang-480.png" alt="Logo" /><span>深入Go语言之旅</span>
|
|
|
</a>
|
|
|
</h2>
|
|
|
|
|
|
|
|
|
<div class="book-search">
|
|
|
<input type="text" id="book-search-input" placeholder="Search" aria-label="Search" maxlength="64" data-hotkeys="s/" />
|
|
|
<div class="book-search-spinner hidden"></div>
|
|
|
<ul id="book-search-results"></ul>
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<ul>
|
|
|
|
|
|
<li>
|
|
|
<a href="https://www.cyub.vip/" target="_blank" rel="noopener">
|
|
|
个人博客
|
|
|
</a>
|
|
|
</li>
|
|
|
|
|
|
<li>
|
|
|
<a href="https://github.com/cyub" target="_blank" rel="noopener">
|
|
|
Github主页
|
|
|
</a>
|
|
|
</li>
|
|
|
|
|
|
<li>
|
|
|
<a href="https://www.topgoer.cn/?ref=go.cyub.vip" target="_blank" rel="noopener">
|
|
|
地鼠文档
|
|
|
</a>
|
|
|
</li>
|
|
|
|
|
|
</ul>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<ul>
|
|
|
<li>
|
|
|
<p><strong>
|
|
|
<a href="/">深入Go语言之旅</a></strong></p>
|
|
|
</li>
|
|
|
<li>
|
|
|
<p><strong>准备篇</strong></p>
|
|
|
<ul>
|
|
|
<li>
|
|
|
<a href="/compiler/">编译流程</a></li>
|
|
|
<li>
|
|
|
<a href="/analysis-tools/">分析工具</a>
|
|
|
<ul>
|
|
|
<li>
|
|
|
<a href="/analysis-tools/gdb/">GDB</a></li>
|
|
|
<li>
|
|
|
<a href="/analysis-tools/dlv/"class=active>Delve</a></li>
|
|
|
<li>
|
|
|
<a href="/analysis-tools/go-buildin-tools/">Go 内置工具</a></li>
|
|
|
</ul>
|
|
|
</li>
|
|
|
<li>
|
|
|
<a href="/go-assembly/">Go汇编</a></li>
|
|
|
</ul>
|
|
|
</li>
|
|
|
<li>
|
|
|
<p><strong>基础篇</strong></p>
|
|
|
<ul>
|
|
|
<li>
|
|
|
<a href="/type/">数据类型与数据结构</a>
|
|
|
<ul>
|
|
|
<li>
|
|
|
<a href="/type/string/">字符串</a></li>
|
|
|
<li>
|
|
|
<a href="/type/array/">数组</a></li>
|
|
|
<li>
|
|
|
<a href="/type/slice/">切片</a></li>
|
|
|
<li>
|
|
|
<a href="/type/nil/">nil</a></li>
|
|
|
<li>
|
|
|
<a href="/type/empty_struct/">空结构体</a></li>
|
|
|
<li>
|
|
|
<a href="/type/pointer/">指针</a></li>
|
|
|
<li>
|
|
|
<a href="/type/map/">映射</a></li>
|
|
|
</ul>
|
|
|
</li>
|
|
|
<li>
|
|
|
<a href="/function/">函数</a>
|
|
|
<ul>
|
|
|
<li>
|
|
|
<a href="/function/first-class/">一等公民</a></li>
|
|
|
<li>
|
|
|
<a href="/function/call-stack/">函数调用栈</a></li>
|
|
|
<li>
|
|
|
<a href="/function/pass-by-value/">值传递</a></li>
|
|
|
<li>
|
|
|
<a href="/function/closure/">闭包</a></li>
|
|
|
<li>
|
|
|
<a href="/function/method/">方法</a></li>
|
|
|
</ul>
|
|
|
</li>
|
|
|
<li>
|
|
|
<a href="/feature/">语言特性</a>
|
|
|
<ul>
|
|
|
<li>
|
|
|
<a href="/feature/comma-ok/">逗号ok模式</a></li>
|
|
|
<li>
|
|
|
<a href="/feature/for-range/">遍历 - for-range语法</a></li>
|
|
|
<li>
|
|
|
<a href="/feature/defer/">延迟执行 - defer语法</a></li>
|
|
|
<li>
|
|
|
<a href="/feature/select/">通道选择器 - select语法</a></li>
|
|
|
<li>
|
|
|
<a href="/feature/panic-recover/">恐慌与恢复 - panic/recover</a></li>
|
|
|
</ul>
|
|
|
</li>
|
|
|
</ul>
|
|
|
</li>
|
|
|
<li>
|
|
|
<p><strong>运行时篇</strong></p>
|
|
|
<ul>
|
|
|
<li>
|
|
|
<a href="/concurrency/">并发编程</a>
|
|
|
<ul>
|
|
|
<li>
|
|
|
<a href="/concurrency/memory-model/">内存模型</a></li>
|
|
|
<li>
|
|
|
<a href="/concurrency/context/">上下文 - context</a></li>
|
|
|
<li>
|
|
|
<a href="/concurrency/channel/">通道 - channel</a></li>
|
|
|
<li>
|
|
|
<a href="/concurrency/atomic/">原子操作 - atomic</a></li>
|
|
|
<li>
|
|
|
<a href="/concurrency/sync-map/">并发Map - sync.Map</a></li>
|
|
|
<li>
|
|
|
<a href="/concurrency/sync-waitgroup/">等待组 - sync.WaitGroup</a></li>
|
|
|
<li>
|
|
|
<a href="/concurrency/sync-once/">一次性操作 - sync.Once</a></li>
|
|
|
<li>
|
|
|
<a href="/concurrency/sync-pool/">缓冲池 - sync.Pool</a></li>
|
|
|
<li>
|
|
|
<a href="/concurrency/sync-cond/">条件变量 - sync.Cond</a></li>
|
|
|
<li>
|
|
|
<a href="/concurrency/sync-mutex/">互斥锁 - sync.Mutex</a></li>
|
|
|
<li>
|
|
|
<a href="/concurrency/sync-rwmutex/">读写锁 - sync.RWMutex</a></li>
|
|
|
</ul>
|
|
|
</li>
|
|
|
<li>
|
|
|
<a href="/gmp/">G-M-P调度机制</a>
|
|
|
<ul>
|
|
|
<li>
|
|
|
<a href="/gmp/gmp-model/">调度机制概述</a></li>
|
|
|
<li>
|
|
|
<a href="/gmp/scheduler/">调度器</a></li>
|
|
|
</ul>
|
|
|
</li>
|
|
|
<li>
|
|
|
<a href="/memory/">内存管理</a>
|
|
|
<ul>
|
|
|
<li>
|
|
|
<a href="/memory/allocator/">内存分配器</a></li>
|
|
|
<li>
|
|
|
<a href="/memory/gc/">GC</a></li>
|
|
|
</ul>
|
|
|
</li>
|
|
|
<li>
|
|
|
<a href="/type-system/">类型系统</a>
|
|
|
<ul>
|
|
|
<li>
|
|
|
<a href="/type-system/type/">类型系统</a></li>
|
|
|
<li>
|
|
|
<a href="/type-system/interface/">接口</a></li>
|
|
|
<li>
|
|
|
<a href="/type-system/reflect/">反射</a></li>
|
|
|
</ul>
|
|
|
</li>
|
|
|
</ul>
|
|
|
</li>
|
|
|
</ul>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</nav>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<script>(function(){var e=document.querySelector("aside .book-menu-content");addEventListener("beforeunload",function(){localStorage.setItem("menu.scrollTop",e.scrollTop)}),e.scrollTop=localStorage.getItem("menu.scrollTop")})()</script>
|
|
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
</aside>
|
|
|
|
|
|
<div class="book-page">
|
|
|
<header class="book-header">
|
|
|
|
|
|
<div class="flex align-center justify-between">
|
|
|
<label for="menu-control">
|
|
|
<img src="/svg/menu.svg" class="book-icon" alt="Menu" />
|
|
|
</label>
|
|
|
|
|
|
<strong>Delve is a debugger for the Go programming language</strong>
|
|
|
|
|
|
<label for="toc-control">
|
|
|
|
|
|
</label>
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</header>
|
|
|
|
|
|
|
|
|
|
|
|
<article class="markdown"><h1 id="delve">
|
|
|
Delve
|
|
|
<a class="anchor" href="#delve">#</a>
|
|
|
</h1>
|
|
|
<p><strong>Delve</strong><sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> 是使用Go语言实现的,专门用来调试Go程序的工具。它跟 <strong>
|
|
|
<a href="/analysis-tools/gdb/">GDB</a></strong> 工具类似,相比 <strong>
|
|
|
<a href="/analysis-tools/gdb/">GDB</a></strong>,它简单易用,能更好的理解Go语言数据结构和语言特性。它支持打印 <code>goroutine</code> 以及 <code>defer</code> 函数等Go特有语法特性。<strong>Delve</strong> 简称 <code>dlv</code>,后文将以 <code>dlv</code> 代称 <strong>Delve</strong>.</p>
|
|
|
<h2 id="安装">
|
|
|
安装
|
|
|
<a class="anchor" href="#%e5%ae%89%e8%a3%85">#</a>
|
|
|
</h2>
|
|
|
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>go get -u github.com/go-delve/delve/cmd/dlv
|
|
|
</span></span></code></pre></div><h2 id="使用">
|
|
|
使用
|
|
|
<a class="anchor" href="#%e4%bd%bf%e7%94%a8">#</a>
|
|
|
</h2>
|
|
|
<h3 id="开始调试">
|
|
|
开始调试
|
|
|
<a class="anchor" href="#%e5%bc%80%e5%a7%8b%e8%b0%83%e8%af%95">#</a>
|
|
|
</h3>
|
|
|
<p><code>dlv</code> 使用 <code>debug</code> 命令进入调试界面:</p>
|
|
|
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>dlv debug main.go
|
|
|
</span></span></code></pre></div><p>如果当前目录是 <code>main</code> 包所在目录时候,可以不用指定 <code>main.go</code> 文件这个参数的。假定项目结构如下:</p>
|
|
|
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>.
|
|
|
</span></span><span style="display:flex;"><span>├── github.com/me/foo
|
|
|
</span></span><span style="display:flex;"><span>├── cmd
|
|
|
</span></span><span style="display:flex;"><span>│ └── foo
|
|
|
</span></span><span style="display:flex;"><span>│ └── main.go
|
|
|
</span></span><span style="display:flex;"><span>├── pkg
|
|
|
</span></span><span style="display:flex;"><span>│ └── baz
|
|
|
</span></span><span style="display:flex;"><span>│ ├── bar.go
|
|
|
</span></span><span style="display:flex;"><span>│ └── bar_test.go
|
|
|
</span></span></code></pre></div><p>如果当前已在 <code>cmd/foo</code> 目录下,我们可以直接执行 <code>dlv debug</code> 命令开始调试。在任何目录下我们可以使用 <code>dlv debug github.com/me/foo/cmd/foo</code> 开始调试。</p>
|
|
|
<p>如果已构建成二进制可执行文件,我们可以使用 <code>dlv exec</code> 命令开始调试:</p>
|
|
|
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>dlv exec /youpath/go_binary_file
|
|
|
</span></span></code></pre></div><p><strong>对于需要命令行参数才能启动的程序,我们可以通过<code>--</code>来传递命令行参数</strong>,比如如下:</p>
|
|
|
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>dlv debug github.com/me/foo/cmd/foo -- -arg1 value
|
|
|
</span></span><span style="display:flex;"><span>dlv exec /mypath/binary -- --config<span style="color:#f92672">=</span>config.toml
|
|
|
</span></span></code></pre></div><p>对于已经运行的程序,可以使用 <code>attach</code> 命令,进行跟踪调试指定 <code>pid</code> 的Go应用:</p>
|
|
|
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>dlv attach pid
|
|
|
</span></span></code></pre></div><p>除了上面调试 <code>main</code> 包外,<code>dlv</code> 通过 <code>test</code> 子命令还支持调试 <code>test</code> 文件:</p>
|
|
|
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>dlv test github.com/me/foo/pkg/baz
|
|
|
</span></span></code></pre></div><p>接下来我们可以使用 <code>help</code> 命令查看 <code>dlv</code> 支持的命令有哪些:</p>
|
|
|
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#f92672">(</span>dlv<span style="color:#f92672">)</span> help
|
|
|
</span></span><span style="display:flex;"><span>The following commands are available:
|
|
|
</span></span><span style="display:flex;"><span>
|
|
|
</span></span><span style="display:flex;"><span>Running the program:
|
|
|
</span></span><span style="display:flex;"><span> call ------------------------ Resumes process, injecting a <span style="color:#66d9ef">function</span> call <span style="color:#f92672">(</span>EXPERIMENTAL!!!<span style="color:#f92672">)</span>
|
|
|
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">continue</span> <span style="color:#f92672">(</span>alias: c<span style="color:#f92672">)</span> --------- Run <span style="color:#66d9ef">until</span> breakpoint or program termination.
|
|
|
</span></span><span style="display:flex;"><span> next <span style="color:#f92672">(</span>alias: n<span style="color:#f92672">)</span> ------------- Step over to next source line.
|
|
|
</span></span><span style="display:flex;"><span> rebuild --------------------- Rebuild the target executable and restarts it. It does not work <span style="color:#66d9ef">if</span> the executable was not built by delve.
|
|
|
</span></span><span style="display:flex;"><span> restart <span style="color:#f92672">(</span>alias: r<span style="color:#f92672">)</span> ---------- Restart process.
|
|
|
</span></span><span style="display:flex;"><span> step <span style="color:#f92672">(</span>alias: s<span style="color:#f92672">)</span> ------------- Single step through program.
|
|
|
</span></span><span style="display:flex;"><span> step-instruction <span style="color:#f92672">(</span>alias: si<span style="color:#f92672">)</span> Single step a single cpu instruction.
|
|
|
</span></span><span style="display:flex;"><span> stepout <span style="color:#f92672">(</span>alias: so<span style="color:#f92672">)</span> --------- Step out of the current <span style="color:#66d9ef">function</span>.
|
|
|
</span></span><span style="display:flex;"><span>
|
|
|
</span></span><span style="display:flex;"><span>Manipulating breakpoints:
|
|
|
</span></span><span style="display:flex;"><span> break <span style="color:#f92672">(</span>alias: b<span style="color:#f92672">)</span> ------- Sets a breakpoint.
|
|
|
</span></span><span style="display:flex;"><span> breakpoints <span style="color:#f92672">(</span>alias: bp<span style="color:#f92672">)</span> Print out info <span style="color:#66d9ef">for</span> active breakpoints.
|
|
|
</span></span><span style="display:flex;"><span> clear ------------------ Deletes breakpoint.
|
|
|
</span></span><span style="display:flex;"><span> clearall --------------- Deletes multiple breakpoints.
|
|
|
</span></span><span style="display:flex;"><span> condition <span style="color:#f92672">(</span>alias: cond<span style="color:#f92672">)</span> Set breakpoint condition.
|
|
|
</span></span><span style="display:flex;"><span> on --------------------- Executes a command when a breakpoint is hit.
|
|
|
</span></span><span style="display:flex;"><span> trace <span style="color:#f92672">(</span>alias: t<span style="color:#f92672">)</span> ------- Set tracepoint.
|
|
|
</span></span><span style="display:flex;"><span>
|
|
|
</span></span><span style="display:flex;"><span>Viewing program variables and memory:
|
|
|
</span></span><span style="display:flex;"><span> args ----------------- Print <span style="color:#66d9ef">function</span> arguments.
|
|
|
</span></span><span style="display:flex;"><span> display -------------- Print value of an expression every time the program stops.
|
|
|
</span></span><span style="display:flex;"><span> examinemem <span style="color:#f92672">(</span>alias: x<span style="color:#f92672">)</span> Examine memory:
|
|
|
</span></span><span style="display:flex;"><span> locals --------------- Print local variables.
|
|
|
</span></span><span style="display:flex;"><span> print <span style="color:#f92672">(</span>alias: p<span style="color:#f92672">)</span> ----- Evaluate an expression.
|
|
|
</span></span><span style="display:flex;"><span> regs ----------------- Print contents of CPU registers.
|
|
|
</span></span><span style="display:flex;"><span> set ------------------ Changes the value of a variable.
|
|
|
</span></span><span style="display:flex;"><span> vars ----------------- Print package variables.
|
|
|
</span></span><span style="display:flex;"><span> whatis --------------- Prints type of an expression.
|
|
|
</span></span><span style="display:flex;"><span>
|
|
|
</span></span><span style="display:flex;"><span>Listing and switching between threads and goroutines:
|
|
|
</span></span><span style="display:flex;"><span> goroutine <span style="color:#f92672">(</span>alias: gr<span style="color:#f92672">)</span> -- Shows or changes current goroutine
|
|
|
</span></span><span style="display:flex;"><span> goroutines <span style="color:#f92672">(</span>alias: grs<span style="color:#f92672">)</span> List program goroutines.
|
|
|
</span></span><span style="display:flex;"><span> thread <span style="color:#f92672">(</span>alias: tr<span style="color:#f92672">)</span> ----- Switch to the specified thread.
|
|
|
</span></span><span style="display:flex;"><span> threads ---------------- Print out info <span style="color:#66d9ef">for</span> every traced thread.
|
|
|
</span></span><span style="display:flex;"><span>
|
|
|
</span></span><span style="display:flex;"><span>Viewing the call stack and selecting frames:
|
|
|
</span></span><span style="display:flex;"><span> deferred --------- Executes command in the context of a deferred call.
|
|
|
</span></span><span style="display:flex;"><span> down ------------- Move the current frame down.
|
|
|
</span></span><span style="display:flex;"><span> frame ------------ Set the current frame, or execute command on a different frame.
|
|
|
</span></span><span style="display:flex;"><span> stack <span style="color:#f92672">(</span>alias: bt<span style="color:#f92672">)</span> Print stack trace.
|
|
|
</span></span><span style="display:flex;"><span> up --------------- Move the current frame up.
|
|
|
</span></span><span style="display:flex;"><span>
|
|
|
</span></span><span style="display:flex;"><span>Other commands:
|
|
|
</span></span><span style="display:flex;"><span> config --------------------- Changes configuration parameters.
|
|
|
</span></span><span style="display:flex;"><span> disassemble <span style="color:#f92672">(</span>alias: disass<span style="color:#f92672">)</span> Disassembler.
|
|
|
</span></span><span style="display:flex;"><span> edit <span style="color:#f92672">(</span>alias: ed<span style="color:#f92672">)</span> ----------- Open where you are in $DELVE_EDITOR or $EDITOR
|
|
|
</span></span><span style="display:flex;"><span> exit <span style="color:#f92672">(</span>alias: quit | q<span style="color:#f92672">)</span> ----- Exit the debugger.
|
|
|
</span></span><span style="display:flex;"><span> funcs ---------------------- Print list of functions.
|
|
|
</span></span><span style="display:flex;"><span> help <span style="color:#f92672">(</span>alias: h<span style="color:#f92672">)</span> ------------ Prints the help message.
|
|
|
</span></span><span style="display:flex;"><span> libraries ------------------ List loaded dynamic libraries
|
|
|
</span></span><span style="display:flex;"><span> list <span style="color:#f92672">(</span>alias: ls | l<span style="color:#f92672">)</span> ------- Show source code.
|
|
|
</span></span><span style="display:flex;"><span> source --------------------- Executes a file containing a list of delve commands
|
|
|
</span></span><span style="display:flex;"><span> sources -------------------- Print list of source files.
|
|
|
</span></span><span style="display:flex;"><span> types ---------------------- Print list of types
|
|
|
</span></span><span style="display:flex;"><span>
|
|
|
</span></span><span style="display:flex;"><span>Type help followed by a command <span style="color:#66d9ef">for</span> full documentation.
|
|
|
</span></span></code></pre></div><p>接下来我们将以下面代码作为示例演示如何dlv进行调试。</p>
|
|
|
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>
|
|
|
</span></span><span style="display:flex;"><span>
|
|
|
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> <span style="color:#e6db74">"fmt"</span>
|
|
|
</span></span><span style="display:flex;"><span>
|
|
|
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
|
|
|
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">"go"</span>)
|
|
|
</span></span><span style="display:flex;"><span>}
|
|
|
</span></span></code></pre></div><h3 id="设置断点">
|
|
|
设置断点
|
|
|
<a class="anchor" href="#%e8%ae%be%e7%bd%ae%e6%96%ad%e7%82%b9">#</a>
|
|
|
</h3>
|
|
|
<p>当我们使用 <code>dlv debug main.go</code> 命令进行 <code>dlv</code> 调试之后,我们可以设置断点。</p>
|
|
|
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#f92672">(</span>dlv<span style="color:#f92672">)</span> b main.main <span style="color:#75715e"># 在main函数处设置断点</span>
|
|
|
</span></span><span style="display:flex;"><span>Breakpoint <span style="color:#ae81ff">1</span> set at 0x4adf8f <span style="color:#66d9ef">for</span> main.main<span style="color:#f92672">()</span> ./main.go:5
|
|
|
</span></span></code></pre></div><h3 id="继续执行">
|
|
|
继续执行
|
|
|
<a class="anchor" href="#%e7%bb%a7%e7%bb%ad%e6%89%a7%e8%a1%8c">#</a>
|
|
|
</h3>
|
|
|
<p>设置断点之后,我们可以通过 <code>continue</code> 命令,可以简写成 <code>c</code> ,继续执行到我们设置的断点处。</p>
|
|
|
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#f92672">(</span>dlv<span style="color:#f92672">)</span> c
|
|
|
</span></span><span style="display:flex;"><span>> main.main<span style="color:#f92672">()</span> ./main.go:5 <span style="color:#f92672">(</span>hits goroutine<span style="color:#f92672">(</span>1<span style="color:#f92672">)</span>:1 total:1<span style="color:#f92672">)</span> <span style="color:#f92672">(</span>PC: 0x4adf8f<span style="color:#f92672">)</span>
|
|
|
</span></span><span style="display:flex;"><span> 1: package main
|
|
|
</span></span><span style="display:flex;"><span> 2:
|
|
|
</span></span><span style="display:flex;"><span> 3: import <span style="color:#e6db74">"fmt"</span>
|
|
|
</span></span><span style="display:flex;"><span> 4:
|
|
|
</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span>> 5: func main<span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
|
|
|
</span></span><span style="display:flex;"><span> 6: fmt.Println<span style="color:#f92672">(</span><span style="color:#e6db74">"go"</span><span style="color:#f92672">)</span>
|
|
|
</span></span><span style="display:flex;"><span> 7: <span style="color:#f92672">}</span>
|
|
|
</span></span></code></pre></div><p>注意不同于 <strong>
|
|
|
<a href="/analysis-tools/gdb/">GDB</a></strong> 需要执行 <code>run</code> 命令启动应用之后,才能执行 <code>continue</code> 命令。而 <code>dlv</code> 在进入调试界面之后,已经指向程序的入口地址处,可以直接执行 <code>continue</code> 命令</p>
|
|
|
<h3 id="执行下一条指令">
|
|
|
执行下一条指令
|
|
|
<a class="anchor" href="#%e6%89%a7%e8%a1%8c%e4%b8%8b%e4%b8%80%e6%9d%a1%e6%8c%87%e4%bb%a4">#</a>
|
|
|
</h3>
|
|
|
<p>我们可以通过next命令,可以简写成<code>n</code>,来执行下一行源码。同 <strong>
|
|
|
<a href="/analysis-tools/gdb/">GDB</a></strong> 一样,<code>next</code> 命令是 <code>Step over</code> 操作,遇到函数时不会进入函数内部一行行代码执行,而是直接执行函数,然后跳过到函数下面的一行代码。</p>
|
|
|
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#f92672">(</span>dlv<span style="color:#f92672">)</span> n
|
|
|
</span></span><span style="display:flex;"><span>go
|
|
|
</span></span><span style="display:flex;"><span>> main.main<span style="color:#f92672">()</span> ./main.go:7 <span style="color:#f92672">(</span>PC: 0x4adfff<span style="color:#f92672">)</span>
|
|
|
</span></span><span style="display:flex;"><span> 2:
|
|
|
</span></span><span style="display:flex;"><span> 3: import <span style="color:#e6db74">"fmt"</span>
|
|
|
</span></span><span style="display:flex;"><span> 4:
|
|
|
</span></span><span style="display:flex;"><span> 5: func main<span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
|
|
|
</span></span><span style="display:flex;"><span> 6: fmt.Println<span style="color:#f92672">(</span><span style="color:#e6db74">"go"</span><span style="color:#f92672">)</span>
|
|
|
</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span>> 7: <span style="color:#f92672">}</span>
|
|
|
</span></span></code></pre></div><h3 id="打印栈信息">
|
|
|
打印栈信息
|
|
|
<a class="anchor" href="#%e6%89%93%e5%8d%b0%e6%a0%88%e4%bf%a1%e6%81%af">#</a>
|
|
|
</h3>
|
|
|
<p>通过 <code>stack</code> 命令,我们可以查看函数栈信息:</p>
|
|
|
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#f92672">(</span>dlv<span style="color:#f92672">)</span> stack
|
|
|
</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0</span> 0x00000000004adfff in main.main
|
|
|
</span></span><span style="display:flex;"><span> at ./main.go:7
|
|
|
</span></span><span style="display:flex;"><span><span style="color:#ae81ff">1</span> 0x0000000000436be8 in runtime.main
|
|
|
</span></span><span style="display:flex;"><span> at /usr/lib/go/src/runtime/proc.go:203
|
|
|
</span></span><span style="display:flex;"><span><span style="color:#ae81ff">2</span> 0x0000000000464621 in runtime.goexit
|
|
|
</span></span><span style="display:flex;"><span> at /usr/lib/go/src/runtime/asm_amd64.s:1373
|
|
|
</span></span></code></pre></div><h3 id="打印gorountine信息">
|
|
|
打印gorountine信息
|
|
|
<a class="anchor" href="#%e6%89%93%e5%8d%b0gorountine%e4%bf%a1%e6%81%af">#</a>
|
|
|
</h3>
|
|
|
<p>通过<code>goroutines</code>命令,可以简写成<code>grs</code>,我们可以查看所有 <code>goroutine</code>:</p>
|
|
|
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#f92672">(</span>dlv<span style="color:#f92672">)</span> goroutines
|
|
|
</span></span><span style="display:flex;"><span>* Goroutine <span style="color:#ae81ff">1</span> - User: ./main.go:7 main.main <span style="color:#f92672">(</span>0x4adfff<span style="color:#f92672">)</span> <span style="color:#f92672">(</span>thread 14358<span style="color:#f92672">)</span>
|
|
|
</span></span><span style="display:flex;"><span> Goroutine <span style="color:#ae81ff">2</span> - User: /usr/lib/go/src/runtime/proc.go:305 runtime.gopark <span style="color:#f92672">(</span>0x436f9b<span style="color:#f92672">)</span>
|
|
|
</span></span><span style="display:flex;"><span> Goroutine <span style="color:#ae81ff">3</span> - User: /usr/lib/go/src/runtime/proc.go:305 runtime.gopark <span style="color:#f92672">(</span>0x436f9b<span style="color:#f92672">)</span>
|
|
|
</span></span><span style="display:flex;"><span> Goroutine <span style="color:#ae81ff">4</span> - User: /usr/lib/go/src/runtime/proc.go:305 runtime.gopark <span style="color:#f92672">(</span>0x436f9b<span style="color:#f92672">)</span>
|
|
|
</span></span><span style="display:flex;"><span> Goroutine <span style="color:#ae81ff">5</span> - User: /usr/lib/go/src/runtime/mfinal.go:161 runtime.runfinq <span style="color:#f92672">(</span>0x418f80<span style="color:#f92672">)</span>
|
|
|
</span></span><span style="display:flex;"><span><span style="color:#f92672">[</span><span style="color:#ae81ff">5</span> goroutines<span style="color:#f92672">]</span>
|
|
|
</span></span></code></pre></div><p><code>goroutine</code> 命令,可以简写成 <code>gr</code>,用来显示当前 <code>goroutine</code> 信息:</p>
|
|
|
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#f92672">(</span>dlv<span style="color:#f92672">)</span> goroutine
|
|
|
</span></span><span style="display:flex;"><span>Thread <span style="color:#ae81ff">14358</span> at ./main.go:7
|
|
|
</span></span><span style="display:flex;"><span>Goroutine 1:
|
|
|
</span></span><span style="display:flex;"><span> Runtime: ./main.go:7 main.main <span style="color:#f92672">(</span>0x4adfff<span style="color:#f92672">)</span>
|
|
|
</span></span><span style="display:flex;"><span> User: ./main.go:7 main.main <span style="color:#f92672">(</span>0x4adfff<span style="color:#f92672">)</span>
|
|
|
</span></span><span style="display:flex;"><span> Go: /usr/lib/go/src/runtime/asm_amd64.s:220 runtime.rt0_go <span style="color:#f92672">(</span>0x462594<span style="color:#f92672">)</span>
|
|
|
</span></span><span style="display:flex;"><span> Start: /usr/lib/go/src/runtime/proc.go:113 runtime.main <span style="color:#f92672">(</span>0x436a20<span style="color:#f92672">)</span>
|
|
|
</span></span></code></pre></div><h3 id="查看汇编代码">
|
|
|
查看汇编代码
|
|
|
<a class="anchor" href="#%e6%9f%a5%e7%9c%8b%e6%b1%87%e7%bc%96%e4%bb%a3%e7%a0%81">#</a>
|
|
|
</h3>
|
|
|
<p>通过 <code>disassemble</code> 命令,可以简写成 <code>disass</code> ,我们可以查看汇编代码:</p>
|
|
|
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#f92672">(</span>dlv<span style="color:#f92672">)</span> disass
|
|
|
</span></span><span style="display:flex;"><span>TEXT main.main<span style="color:#f92672">(</span>SB<span style="color:#f92672">)</span> /tmp/dlv/main.go
|
|
|
</span></span><span style="display:flex;"><span> main.go:5 0x4adf80 64488b0c25f8ffffff mov rcx, qword ptr fs:<span style="color:#f92672">[</span>0xfffffff8<span style="color:#f92672">]</span>
|
|
|
</span></span><span style="display:flex;"><span> main.go:5 0x4adf89 483b6110 cmp rsp, qword ptr <span style="color:#f92672">[</span>rcx+0x10<span style="color:#f92672">]</span>
|
|
|
</span></span><span style="display:flex;"><span> main.go:5 0x4adf8d 767a jbe 0x4ae009
|
|
|
</span></span><span style="display:flex;"><span> main.go:5 0x4adf8f* 4883ec68 sub rsp, 0x68
|
|
|
</span></span><span style="display:flex;"><span> main.go:5 0x4adf93 48896c2460 mov qword ptr <span style="color:#f92672">[</span>rsp+0x60<span style="color:#f92672">]</span>, rbp
|
|
|
</span></span><span style="display:flex;"><span> main.go:5 0x4adf98 488d6c2460 lea rbp, ptr <span style="color:#f92672">[</span>rsp+0x60<span style="color:#f92672">]</span>
|
|
|
</span></span><span style="display:flex;"><span> main.go:6 0x4adf9d 0f57c0 xorps xmm0, xmm0
|
|
|
</span></span><span style="display:flex;"><span> main.go:6 0x4adfa0 0f11442438 movups xmmword ptr <span style="color:#f92672">[</span>rsp+0x38<span style="color:#f92672">]</span>, xmm0
|
|
|
</span></span><span style="display:flex;"><span> main.go:6 0x4adfa5 488d442438 lea rax, ptr <span style="color:#f92672">[</span>rsp+0x38<span style="color:#f92672">]</span>
|
|
|
</span></span><span style="display:flex;"><span> main.go:6 0x4adfaa 4889442430 mov qword ptr <span style="color:#f92672">[</span>rsp+0x30<span style="color:#f92672">]</span>, rax
|
|
|
</span></span><span style="display:flex;"><span> main.go:6 0x4adfaf 8400 test byte ptr <span style="color:#f92672">[</span>rax<span style="color:#f92672">]</span>, al
|
|
|
</span></span><span style="display:flex;"><span> main.go:6 0x4adfb1 488d0d28ed0000 lea rcx, ptr <span style="color:#f92672">[</span>rip+0xed28<span style="color:#f92672">]</span>
|
|
|
</span></span><span style="display:flex;"><span> main.go:6 0x4adfb8 48894c2438 mov qword ptr <span style="color:#f92672">[</span>rsp+0x38<span style="color:#f92672">]</span>, rcx
|
|
|
</span></span><span style="display:flex;"><span> main.go:6 0x4adfbd 488d0dcce10300 lea rcx, ptr <span style="color:#f92672">[</span>rip+0x3e1cc<span style="color:#f92672">]</span>
|
|
|
</span></span><span style="display:flex;"><span> main.go:6 0x4adfc4 48894c2440 mov qword ptr <span style="color:#f92672">[</span>rsp+0x40<span style="color:#f92672">]</span>, rcx
|
|
|
</span></span><span style="display:flex;"><span> main.go:6 0x4adfc9 8400 test byte ptr <span style="color:#f92672">[</span>rax<span style="color:#f92672">]</span>, al
|
|
|
</span></span><span style="display:flex;"><span> main.go:6 0x4adfcb eb00 jmp 0x4adfcd
|
|
|
</span></span><span style="display:flex;"><span> main.go:6 0x4adfcd 4889442448 mov qword ptr <span style="color:#f92672">[</span>rsp+0x48<span style="color:#f92672">]</span>, rax
|
|
|
</span></span><span style="display:flex;"><span> main.go:6 0x4adfd2 48c744245001000000 mov qword ptr <span style="color:#f92672">[</span>rsp+0x50<span style="color:#f92672">]</span>, 0x1
|
|
|
</span></span><span style="display:flex;"><span> main.go:6 0x4adfdb 48c744245801000000 mov qword ptr <span style="color:#f92672">[</span>rsp+0x58<span style="color:#f92672">]</span>, 0x1
|
|
|
</span></span><span style="display:flex;"><span> main.go:6 0x4adfe4 48890424 mov qword ptr <span style="color:#f92672">[</span>rsp<span style="color:#f92672">]</span>, rax
|
|
|
</span></span><span style="display:flex;"><span> main.go:6 0x4adfe8 48c744240801000000 mov qword ptr <span style="color:#f92672">[</span>rsp+0x8<span style="color:#f92672">]</span>, 0x1
|
|
|
</span></span><span style="display:flex;"><span> main.go:6 0x4adff1 48c744241001000000 mov qword ptr <span style="color:#f92672">[</span>rsp+0x10<span style="color:#f92672">]</span>, 0x1
|
|
|
</span></span><span style="display:flex;"><span> main.go:6 0x4adffa e811a1ffff call $fmt.Println
|
|
|
</span></span><span style="display:flex;"><span><span style="color:#f92672">=</span>> main.go:7 0x4adfff 488b6c2460 mov rbp, qword ptr <span style="color:#f92672">[</span>rsp+0x60<span style="color:#f92672">]</span>
|
|
|
</span></span><span style="display:flex;"><span> main.go:7 0x4ae004 4883c468 add rsp, 0x68
|
|
|
</span></span><span style="display:flex;"><span> main.go:7 0x4ae008 c3 ret
|
|
|
</span></span><span style="display:flex;"><span> main.go:5 0x4ae009 e8e247fbff call $runtime.morestack_noctxt
|
|
|
</span></span><span style="display:flex;"><span> <autogenerated>:1 0x4ae00e e96dffffff jmp $main.main
|
|
|
</span></span></code></pre></div><p><code>dlv</code> 默认显示的是 <code>intel</code> 风格汇编代码,我们可以通过 <code>config</code> 命令设置 <code>gnu</code> 或者 <code>go</code> 风格代码:</p>
|
|
|
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#f92672">(</span>dlv<span style="color:#f92672">)</span> config disassemble-flavor go
|
|
|
</span></span></code></pre></div><p>这种方式更改的配置只会对此次调试有效,若保证下次调试一样有效,我们需要将其配置到配置文件中。<code>dlv</code> 默认配置文件是 <code>HOME/.config/dlv/config.yml</code>。我们只需要在配置文件加入以下内容:</p>
|
|
|
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">disassemble-flavor</span>: <span style="color:#ae81ff">go</span>
|
|
|
</span></span></code></pre></div><div class="footnotes" role="doc-endnotes">
|
|
|
<hr>
|
|
|
<ol>
|
|
|
<li id="fn:1">
|
|
|
<p>
|
|
|
<a href="https://github.com/go-delve/delve">https://github.com/go-delve/delve</a> <a href="#fnref:1" class="footnote-backref" role="doc-backlink">↩︎</a></p>
|
|
|
</li>
|
|
|
</ol>
|
|
|
</div>
|
|
|
</article>
|
|
|
|
|
|
|
|
|
|
|
|
<footer class="book-footer">
|
|
|
|
|
|
<div class="flex flex-wrap justify-between">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<script>(function(){function e(e){const t=window.getSelection(),n=document.createRange();n.selectNodeContents(e),t.removeAllRanges(),t.addRange(n)}document.querySelectorAll("pre code").forEach(t=>{t.addEventListener("click",function(){if(window.getSelection().toString())return;e(t.parentElement),navigator.clipboard&&navigator.clipboard.writeText(t.parentElement.textContent)})})})()</script>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</footer>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="book-comments">
|
|
|
|
|
|
<script src="https://giscus.app/client.js" data-repo="cyub/go-1.14.13"
|
|
|
data-repo-id="MDEwOlJlcG9zaXRvcnkzMzc2ODUyMzQ=" data-category="Announcements"
|
|
|
data-category-id="DIC_kwDOFCCq8s4CZ3BC"
|
|
|
data-mapping="pathname" data-strict="0" data-emit-metadata="0"
|
|
|
data-input-position="bottom" data-reactions-enabled="0"
|
|
|
data-lang="zh-CN" data-theme="preferred_color_scheme" crossorigin="anonymous" async>
|
|
|
</script>
|
|
|
<noscript>Please enable JavaScript to view the comments powered by giscus.</noscript>
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<label for="menu-control" class="hidden book-menu-overlay"></label>
|
|
|
</div>
|
|
|
|
|
|
|
|
|
</main>
|
|
|
|
|
|
|
|
|
</body>
|
|
|
</html>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|