<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
<meta name="Generator" content="Microsoft Word 15 (filtered medium)">
<style><!--
/* Font Definitions */
@font-face
{font-family:"Cambria Math";
panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
{font-family:Calibri;
panose-1:2 15 5 2 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{margin:0in;
font-size:11.0pt;
font-family:"Calibri",sans-serif;}
span.EmailStyle19
{mso-style-type:personal-reply;
font-family:"Calibri",sans-serif;
color:windowtext;}
.MsoChpDefault
{mso-style-type:export-only;
font-size:10.0pt;}
@page WordSection1
{size:8.5in 11.0in;
margin:1.0in 1.0in 1.0in 1.0in;}
div.WordSection1
{page:WordSection1;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]-->
</head>
<body lang="EN-US" link="#0563C1" vlink="#954F72" style="word-wrap:break-word">
<div class="WordSection1">
<p class="MsoNormal">In functions without a frame pointer, emitting a one-instruction location range at every push/pop (for a potentially large set of stack-homed local variables) does seem like it would take up a lot of space for not much real-world benefit.<o:p></o:p></p>
<p class="MsoNormal">On the other hand, having a location range that covers the actual call instruction (or I suppose, more precisely, its return address) would make the locals available to the user when the debugger is stopped in the callee, and that seems
*<b>very</b>* valuable.<o:p></o:p></p>
<p class="MsoNormal">Wondering what other people think.<o:p></o:p></p>
<p class="MsoNormal">--paulr<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<div style="border:none;border-left:solid blue 1.5pt;padding:0in 0in 0in 4.0pt">
<div>
<div style="border:none;border-top:solid #E1E1E1 1.0pt;padding:3.0pt 0in 0in 0in">
<p class="MsoNormal"><b>From:</b> llvm-dev <llvm-dev-bounces@lists.llvm.org> <b>On Behalf Of
</b>via llvm-dev<br>
<b>Sent:</b> Thursday, May 6, 2021 1:51 PM<br>
<b>To:</b> llvm-dev@lists.llvm.org<br>
<b>Subject:</b> [llvm-dev] [debug-info] Stack pointer based variable locations<o:p></o:p></p>
</div>
</div>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"><span lang="EN-GB">Hello llvm-dev,<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB">I've noticed some behaviour I found surprising with the way that we emit stack pointer relative<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB">variable locations. It seems that locations defined by DBG_VALUEs that are written in terms of RSP<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB">(for x86) are terminated by any stack manipulation operations, e.g. pushing arguments before a<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB">call. Since we know the stack offset at each adjustment it seems like we could maintain the variable<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB">location by generating location list entries with adjusted RSP offsets.<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB">Here's a source reproducer with clang built at 71597d40e878 (recent), target<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB">x86_64-unknown-linux-gnu).<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB">$ cat test.cpp<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB">void ext(int, int, int, int, int, int, int, int, int, int);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB">void escape(int*);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB">int example() {<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB"> int local = 0;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB"> escape(&local);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB"> ext(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB"> local += 2;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB"> return local;<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB">}<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB">$ clang -O2 -g -c test.cpp -o test.o<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB">$ llvm-objdump -d test.o<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB">test.o: file format elf64-x86-64<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB">Disassembly of section .text:<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB">0000000000000000 <_Z7examplev>:<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB"> 0: 50 pushq %rax<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB"> 1: c7 44 24 04 00 00 00 00 movl $0, 4(%rsp)<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB"> 9: 48 8d 7c 24 04 leaq 4(%rsp), %rdi<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB"> e: e8 00 00 00 00 callq 0x13 <_Z7examplev+0x13><o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB"> 13: 31 ff xorl %edi, %edi<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB"> 15: be 01 00 00 00 movl $1, %esi<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB"> 1a: ba 02 00 00 00 movl $2, %edx<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB"> 1f: b9 03 00 00 00 movl $3, %ecx<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB"> 24: 41 b8 04 00 00 00 movl $4, %r8d<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB"> 2a: 41 b9 05 00 00 00 movl $5, %r9d<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB"> 30: 6a 09 pushq $9<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB"> 32: 6a 08 pushq $8<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB"> 34: 6a 07 pushq $7<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB"> 36: 6a 06 pushq $6<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB"> 38: e8 00 00 00 00 callq 0x3d <_Z7examplev+0x3d><o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB"> 3d: 48 83 c4 20 addq $32, %rsp<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB"> 41: 8b 44 24 04 movl 4(%rsp), %eax<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB"> 45: 83 c0 02 addl $2, %eax<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB"> 48: 59 popq %rcx<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB"> 49: c3 retq<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB">$ llvm-dwarfdump test.o --name local<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB">test.o: file format elf64-x86-64<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB">0x00000047: DW_TAG_variable<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB"> DW_AT_location (0x00000000:
<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB"> [0x0000000000000001, 0x0000000000000009): DW_OP_consts +0, DW_OP_stack_value<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB"> [0x0000000000000009, 0x0000000000000032): DW_OP_breg7 RSP+4<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB"> [0x0000000000000045, 0x000000000000004a): DW_OP_reg0 RAX)<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB"> DW_AT_name ("local")<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB"> DW_AT_decl_file ("/home/och/dev/bugs/scratch/test.cpp")<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB"> DW_AT_decl_line (4)<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB"> DW_AT_type (0x000000ad "int")<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB">The variable 'local' is not given a location over the interval [32, 45) even though we<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB">know where it is (RSP+8, RSP+12, ..., back to RSP+4 after the stack adjustment following the<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB">call). It seems unfortunate to lose variable locations in this way, especially around call sites. Is<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB">this a deliberate omission, perhaps made in order to save space? Jeremy mentioned that we do<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-bottom:12.0pt"><span lang="EN-GB">something similar in prologues/epilogues to avoid generating large location lists.<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB">Many thanks,<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-GB">Orlando<o:p></o:p></span></p>
</div>
</div>
</body>
</html>