From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 16527 invoked by alias); 15 Nov 2010 17:28:30 -0000 Received: (qmail 16517 invoked by uid 22791); 15 Nov 2010 17:28:27 -0000 X-SWARE-Spam-Status: No, hits=-1.2 required=5.0 tests=AWL,BAYES_00,MSGID_MULTIPLE_AT,TW_OV X-Spam-Check-By: sourceware.org Received: from mailhost.u-strasbg.fr (HELO mailhost.u-strasbg.fr) (130.79.200.156) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 15 Nov 2010 17:27:51 +0000 Received: from md1.u-strasbg.fr (md1.u-strasbg.fr [IPv6:2001:660:2402::186]) by mailhost.u-strasbg.fr (8.14.3/jtpda-5.5pre1) with ESMTP id oAFHRhMo081345 for ; Mon, 15 Nov 2010 18:27:43 +0100 (CET) (envelope-from pierre.muller@ics-cnrs.unistra.fr) Received: from mailserver.u-strasbg.fr (ms1.u-strasbg.fr [IPv6:2001:660:2402:d::10]) by md1.u-strasbg.fr (8.14.4/jtpda-5.5pre1) with ESMTP id oAFHRgK6048619 for ; Mon, 15 Nov 2010 18:27:42 +0100 (CET) (envelope-from pierre.muller@ics-cnrs.unistra.fr) Received: from E6510Muller (gw-ics.u-strasbg.fr [130.79.210.225]) (user=mullerp mech=LOGIN) by mailserver.u-strasbg.fr (8.14.4/jtpda-5.5pre1) with ESMTP id oAFHRgEj037914 (version=TLSv1/SSLv3 cipher=AES128-SHA bits=128 verify=NO) for ; Mon, 15 Nov 2010 18:27:42 +0100 (CET) (envelope-from pierre.muller@ics-cnrs.unistra.fr) From: "Pierre Muller" To: Subject: [RFC] Improve amd64 prologue analysis Date: Mon, 15 Nov 2010 17:28:00 -0000 Message-ID: <001701cb84ea$6883c170$398b4450$@muller@ics-cnrs.unistra.fr> MIME-Version: 1.0 Content-Type: text/plain; charset="US-ASCII" Content-Transfer-Encoding: 7bit Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2010-11/txt/msg00177.txt.bz2 Free Pascal for x86_64 (amd64) CPU generates losts of functions that do not use RBP as a frame pointer. I tried to improve amd64-tdep.c to better cope with this case. The patch does mainly two things: 1) Fix the subl val,%rsp (the REX prefix was missing) 2) Add a new function called amd64_analyze_register_saves that tries to support: pushq %reg movq %reg,ofs(%rsp) and movq %reg,ofs(%rbp) It took me a while to understand the generated code, but I hope that I don't get any false positives concerning register saves. The output for a Free Pascal compiled program greatly improved with that patch. On the other hand, testing on complier farm x86_64-unknown-linux-gnu showed no changes in the testsuite results, which was a disappointment for me... Comments most welcome. Pierre Muller GDB pascal language maintainer 2010-11-15 Pierre Muller * amd64-tdep.c (struct amd64_frame_cache): Add LOCALS field. (amd64_init_frame_cache): Set LOCALS field to -1. (amd64_analyze_register_saves): New function. (amd64_analyze_prologue): Correct analyzis of 'subl val,%rsp' and call amd64_analyze_register_saves. Index: src/gdb/amd64-tdep.c =================================================================== RCS file: /cvs/src/src/gdb/amd64-tdep.c,v retrieving revision 1.82 diff -u -p -r1.82 amd64-tdep.c --- src/gdb/amd64-tdep.c 11 Sep 2010 19:09:34 -0000 1.82 +++ src/gdb/amd64-tdep.c 15 Nov 2010 16:55:55 -0000 @@ -1629,6 +1629,7 @@ struct amd64_frame_cache /* Do we have a frame? */ int frameless_p; + long locals; }; /* Initialize a frame cache. */ @@ -1642,6 +1643,7 @@ amd64_init_frame_cache (struct amd64_fra cache->base = 0; cache->sp_offset = -8; cache->pc = 0; + cache->locals = -1; /* Saved registers. We initialize these to -1 since zero is a valid offset (that's where %rbp is supposed to be stored). @@ -1824,6 +1826,123 @@ amd64_analyze_stack_align (CORE_ADDR pc, return min (pc + offset + 2, current_pc); } +/* Check whether PC points at code that saves registers on the stack. + If so, it updates CACHE and returns the address of the first + instruction after the register saves or CURRENT_PC, whichever is + smaller. Otherwise, return PC. */ + +static CORE_ADDR +amd64_analyze_register_saves (CORE_ADDR pc, CORE_ADDR current_pc, + struct amd64_frame_cache *cache, + enum bfd_endian byte_order) +{ + CORE_ADDR offset = 0; + gdb_byte op, opa[5]; + int i, loc, regnum, has_rex_prefix; + gdb_byte modrm, mod, reg1, reg2; + + if (cache->locals > 0) + offset -= cache->locals; + /* pushq $reg */ + for (i = 0; i < 16 && pc < current_pc; i++) + { + target_read_memory (pc, &op, 1); + regnum = 0; + has_rex_prefix = 0; + /* REX prefix might be used for r8-r15 registers. */ + if (rex_prefix_p (op)) + { + /* Typically 0x41 will be used. + Prefix for r8-r15 registers. */ + regnum = (op & 1) ? 8 : 0; + target_read_memory (pc + 1, &op, 1); + has_rex_prefix = 1; + } + if (op < 0x50 || op > 0x57) + break; + + offset -= 8; + regnum += op -0x50; + if (regnum < AMD64_NUM_SAVED_REGS) + cache->saved_regs[amd64_arch_regmap[regnum]] = offset; + cache->sp_offset += 8; + /* Skip 2 bytes for r8-r15, one otherwise. */ + if (has_rex_prefix) + pc++; + pc++; + } + + /* movq $reg,offset (%rsp/%rbp) + exists in two version, with 1byte or 4byte offset. + rbp versions are shorter. */ + for (i = 0; i < 16 * 4 && pc + 4 < current_pc; i++) + { + target_read_memory (pc, opa, 5); + if ((opa[0] != 0x48 && opa[0] !=0x4c) + || opa[1] != 0x89) + break; + modrm = opa[2]; + reg1 = modrm & 7; + reg2 = (modrm >> 3) & 7; + mod = modrm >> 6; + if (mod == 3) /* eliminate movq %reg1,%reg2 */ + break; + + /* %rsp base needs use of SIB byte. */ + if ((reg1 == 4) /* SIB indicator */ + && (opa[3] != 0x24)) + break; + if ((reg1 != 5) && (reg1 != 4)) + break; + + if (opa[0] == 0x4c) + regnum = 8; + else + regnum = 0; + + loc = 0; + if (reg1 == 5) /* Indicator of rbp base */ + { + if (mod == 0) /* This is not rbp base. */ + break; + if (mod == 2) + loc = read_memory_integer (pc + 3, 4, byte_order); + else + loc = opa[3]; + } + else if ((reg1 == 4) && (opa[3] == 0x24)) /* rsp base */ + { + /* 4byte flag is MSB of third byte */ + if (mod == 2) + loc = read_memory_integer (pc + 4, 4, byte_order); + else if (mod == 1) + loc = opa[4]; + else + loc = 0; + /* Add rsp to base offset. */ + loc += offset; + pc++; + } + + regnum += reg2; + + if (regnum < AMD64_NUM_SAVED_REGS) + cache->saved_regs[amd64_arch_regmap[regnum]] = loc; + + /* Advance to next instruction. */ + if (mod == 2) + pc += 7; + else if (mod == 1) + pc += 4; + else + pc += 3; + } + + + return pc; +} + + /* Do a limited analysis of the prologue at PC and update CACHE accordingly. Bail out early if CURRENT_PC is reached. Return the address where the analysis stopped. @@ -1867,13 +1986,45 @@ amd64_analyze_prologue (struct gdbarch * /* Check for `movq %rsp, %rbp'. */ read_memory (pc + 1, buf, 3); if (memcmp (buf, proto, 3) != 0) - return pc + 1; + pc++; + else + { + /* OK, we actually have a frame. */ + cache->frameless_p = 0; + pc += 4; + } + } - /* OK, we actually have a frame. */ - cache->frameless_p = 0; - return pc + 4; + op = read_memory_unsigned_integer (pc, 1, byte_order); + + /* Check for stack adjustment + + subl $XXX, %rsp + + NOTE: You can't subtract a 16-bit immediate from a 64-bit + reg, so we don't have to worry about a data16 prefix. + A REX prefix is required for 64bit sub instruction. */ + if (op == 0x48 && current_pc >= pc + 4) /* subl value,%rsp */ + { + read_memory (pc + 1, buf, 2); + /* Pattern for a 4 byte signed value. */ + if (buf[0] == 0x81 && buf[1] == 0xec) + { + cache->locals = read_memory_integer (pc + 3, 4, byte_order); + cache->sp_offset += cache->locals; + pc = pc + 7; + } + /* Pattern for a 2 byte signed value. */ + else if (buf[0] == 0x83 && buf[1] == 0xec) + { + cache->locals = read_memory_integer (pc + 3, 1, byte_order); + cache->sp_offset += cache->locals; + pc = pc + 4; + } } + pc = amd64_analyze_register_saves (pc, current_pc, cache, byte_order); + return pc; }