From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 118679 invoked by alias); 11 Jan 2017 10:54:00 -0000 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 Received: (qmail 118662 invoked by uid 89); 11 Jan 2017 10:53:59 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.8 required=5.0 tests=AWL,BAYES_00,MIME_BASE64_BLANKS,RCVD_IN_DNSWL_NONE,SPF_HELO_PASS,SPF_PASS,URIBL_RED autolearn=ham version=3.3.2 spammy=Hx-languages-length:2049, H*MI:sk:4553e98, H*f:sk:4553e98, H*i:sk:4553e98 X-HELO: EUR03-AM5-obe.outbound.protection.outlook.com Received: from mail-eopbgr30071.outbound.protection.outlook.com (HELO EUR03-AM5-obe.outbound.protection.outlook.com) (40.107.3.71) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 11 Jan 2017 10:53:49 +0000 Received: from DB6PR0801MB1814.eurprd08.prod.outlook.com (10.169.227.136) by DB6PR0801MB1815.eurprd08.prod.outlook.com (10.169.227.137) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384) id 15.1.817.10; Wed, 11 Jan 2017 10:53:45 +0000 Received: from DB6PR0801MB1814.eurprd08.prod.outlook.com ([10.169.227.136]) by DB6PR0801MB1814.eurprd08.prod.outlook.com ([10.169.227.136]) with mapi id 15.01.0817.020; Wed, 11 Jan 2017 10:53:45 +0000 From: Alan Hayward To: Luis Machado CC: Yao Qi , "gdb-patches@sourceware.org" , nd Subject: Re: [PATCH 2/3] Allocate data in cached_reg_t Date: Wed, 11 Jan 2017 10:54:00 -0000 Message-ID: References: <3BD71BF1-BD32-4952-9E54-8FD14EB54987@arm.com> <29912fac-24a9-afb3-d65e-6d1796fedd14@codesourcery.com> <20170110125905.GF9518@E107787-LIN> <4553e987-6404-8123-eae7-48f85bf62388@codesourcery.com> In-Reply-To: <4553e987-6404-8123-eae7-48f85bf62388@codesourcery.com> authentication-results: spf=none (sender IP is ) smtp.mailfrom=Alan.Hayward@arm.com; x-ms-exchange-messagesentrepresentingtype: 1 x-ms-office365-filtering-correlation-id: aacf8064-a19e-4287-7786-08d43a101d7f x-microsoft-antispam: UriScan:;BCL:0;PCL:0;RULEID:(22001);SRVR:DB6PR0801MB1815; x-microsoft-exchange-diagnostics: 1;DB6PR0801MB1815;7:nEAljaurTUZmqQ83I7ioV8X8UBLHpNLle8dFovbKwvIcKwN+02vRvjiFTpLiw+Z/as+6UKsO0Eyx1YJEcC/Fh/atYOt6wrAyUlshpV2MAd5Iq9C8QFoTreRkJ9rM4wqakgjKFKpMCh9t0jvGjPM8c/aXemasHjDMvmW8c77IpMeqZi9YSa2FCcF/toYQD3VSheW+8QKutKLDN8ZvEhE/LDj7IwmPgkGd2dAPn4kzqIvSB+M3pXZ+zx/jqzLflGYsQV37xtMQw8en/gGdbsXXi70pMTHkV/LQLxgbZ0n++8RbLKKonYWf9iiq3Rr96+5yq6992YkO5ExuE+GjJmADKq7Hto1fKZVkNPSf8UIymW9x37tYRMtL8ieX/jJxLFKYnqGA/62p9hom+CLscJAktD9wXl2jdNFIYleOC84e5OSRToRzWNjUfA/rAxgfQQq/NJcv7mkxzj6Zb7s/T65k7g== nodisclaimer: True x-microsoft-antispam-prvs: x-exchange-antispam-report-test: UriScan:; x-exchange-antispam-report-cfa-test: BCL:0;PCL:0;RULEID:(6040375)(601004)(2401047)(8121501046)(5005006)(3002001)(10201501046)(6055026)(6041248)(20161123564025)(20161123562025)(20161123555025)(20161123560025)(6072148);SRVR:DB6PR0801MB1815;BCL:0;PCL:0;RULEID:;SRVR:DB6PR0801MB1815; x-forefront-prvs: 01842C458A x-forefront-antispam-report: SFV:NSPM;SFS:(10009020)(6009001)(7916002)(39840400002)(39410400002)(39850400002)(39450400003)(39860400002)(377424004)(189002)(377454003)(199003)(24454002)(92566002)(2900100001)(97736004)(122556002)(189998001)(110136003)(6512007)(38730400001)(99286003)(54906002)(6916009)(2950100002)(39060400001)(6486002)(25786008)(7736002)(3660700001)(3280700002)(305945005)(83716003)(36756003)(6436002)(82746002)(229853002)(4326007)(50986999)(101416001)(5660300001)(77096006)(6506006)(76176999)(66066001)(105586002)(106356001)(106116001)(86362001)(68736007)(81166006)(8676002)(8936002)(93886004)(81156014)(33656002)(102836003)(2906002)(6116002)(3846002)(54356999)(104396002);DIR:OUT;SFP:1101;SCL:1;SRVR:DB6PR0801MB1815;H:DB6PR0801MB1814.eurprd08.prod.outlook.com;FPR:;SPF:None;PTR:InfoNoRecords;MX:1;A:1;LANG:en; received-spf: None (protection.outlook.com: arm.com does not designate permitted sender hosts) spamdiagnosticoutput: 1:99 spamdiagnosticmetadata: NSPM Content-Type: text/plain; charset="utf-8" Content-ID: Content-Transfer-Encoding: base64 MIME-Version: 1.0 X-OriginatorOrg: arm.com X-MS-Exchange-CrossTenant-originalarrivaltime: 11 Jan 2017 10:53:45.3361 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: f34e5979-57d9-4aaa-ad4d-b122a662184d X-MS-Exchange-Transport-CrossTenantHeadersStamped: DB6PR0801MB1815 X-SW-Source: 2017-01/txt/msg00182.txt.bz2 DQo+IE9uIDEwIEphbiAyMDE3LCBhdCAxNzo0MiwgTHVpcyBNYWNoYWRvIDxs Z3VzdGF2b0Bjb2Rlc291cmNlcnkuY29tPiB3cm90ZToNCj4gDQo+IE9uIDAx LzEwLzIwMTcgMDY6NTkgQU0sIFlhbyBRaSB3cm90ZToNCj4+IE9uIDE3LTAx LTA5IDE0OjExOjEzLCBMdWlzIE1hY2hhZG8gd3JvdGU6DQo+Pj4+IEBAIC02 MzA2LDcgKzYzMDYsNyBAQCByZW1vdGVfY29uc29sZV9vdXRwdXQgKGNoYXIg Km1zZykNCj4+Pj4gdHlwZWRlZiBzdHJ1Y3QgY2FjaGVkX3JlZw0KPj4+PiB7 DQo+Pj4+ICBpbnQgbnVtOw0KPj4+PiAtICBnZGJfYnl0ZSBkYXRhW01BWF9S RUdJU1RFUl9TSVpFXTsNCj4+Pj4gKyAgZ2RiX2J5dGUgKmRhdGE7DQo+Pj4g DQo+Pj4gV291bGQgaXQgbWFrZSBzZW5zZSB0byBnbyBDKysgYW5kIHVzZSBh IGRhdGEgc3RydWN0dXJlIHRoYXQgY2FuIHRha2UNCj4+PiBjYXJlIG9mIHZh cmlhYmxlIHNpemVzPyBKdXN0IHRoaW5raW5nIGlmIHRoYXQgd291bGQgYmUg ZWFzaWVyIHRoYW4NCj4+PiBoYW5kbGluZyBhbGxvY2F0aW9uL2RlYWxsb2Nh dGlvbiBvZiB0aGUgZGF0YS4NCj4+PiANCj4+IA0KPj4gRG8geW91IHN1Z2dl c3Qgc3RkOjp2ZWN0b3I/ICBXZSBzdGlsbCBuZWVkIHRvIGFsbG9jYXRlL2Rl YWxsb2NhdGUgaXQNCj4+IGlmIHdlIGNoYW5nZSAiZ2RiX2J5dGUgKmRhdGEi IHRvICJzdGQ6OnZlY3RvcjxnZGJfYnl0ZT4gKmRhdGEiLCBvciB3ZQ0KPj4g aGF2ZSB0byBjb252ZXJ0IGNhY2hlZF9yZWcgdG8gY2xhc3MsIGFuZCBkbyBS QUlJLg0KPj4gDQo+IA0KPiBTb21ldGhpbmcgbGlrZSBzdGQ6OnZlY3Rvciwg eWVzLiBCdXQgaXQgaXMgdHJ1ZSB3ZSB3aWxsIHN0aWxsIG5lZWQgdG8gYWxs b2NhdGUgdGhlIHZlY3RvciBpdHNlbGYuDQo+IA0KPiBJIHdhcyBwb25kZXJp bmcgYWJvdXQgdGhlIGJlbmVmaXRzIG9mIG5vdCBiZWluZyBsaW1pdGVkIHRv IGEgc3BlY2lmaWMgcmVnaXN0ZXIgc2l6ZS4gVGhlbiB3ZSB3b3VsZG4ndCBu ZWVkIHRvIHdvcnJ5IGFib3V0IGFkanVzdGluZyB0aGluZ3MgYXMgd2UgaGF2 ZSB0byBkbyBub3cuDQo+IA0KPiBBcyBpIHNlZSBpdCwgZGF0YVtyZWdpc3Rl cl9zaXplKHJlZ2lzdGVyX3NpemUgKGdkYmFyY2gsIG51bSldIHdvdWxkbid0 IGJlIG11Y2ggZGlmZmVyZW50IHRoYW4gZGF0YVtNQVhfUkVHSVNURVJfU0la RV0uIFRoZSBvbmx5IHRoaW5nIGlzIHRoYXQgd2UncmUgc2V0dGluZyB0aGUg bWF4IHJlZ2lzdGVyIHNpemUgZHluYW1pY2FsbHkuDQo+IA0KPiBXZSBtYXkg b3IgbWF5IG5vdCBuZWVkIHRoaXMgZmxleGliaWxpdHkgcmlnaHQgbm93LCBi dXQgd2hvIGtub3dzIHdoYXQgd2VpcmQgYXJjaGl0ZWN0dXJlcyB3ZSBtYXkg aGF2ZSBpbiB0aGUgZnV0dXJlLg0KDQpJIGF2b2lkZWQgdXNpbmcgZGF0YVty ZWdpc3Rlcl9zaXplKGdkYmFyY2gsIG51bSldIGFzIGR5bmFtaWNhbGx5IHNp emVkIGFycmF5cyBhcmUgYSBnY2MgZXh0ZW5zaW9uIC0gaXTigJlzIG5vdCBz b21ldGhpbmcgd2UgY2FuIGV4cGVjdCB0byB3b3JrIG9uIG90aGVyIGNvbXBp bGVycy4NClBsdXMgdGhlcmUgaXMgYSBkYW5nZXIgb2YgaXQgdXNpbmcgdXAg YWxsIHRoZSBzdGFjay4gQWFyY2g2NCBTVkUgd2lsbCBoYXZlIGEgbWF4IHJl Z2lzdGVyIHNpemUgb2YgMjU2LCBwb3RlbnRpYWxseSB0aGlzIGNvdWxkIGdy b3cgZnVydGhlciBpbiB0aGUgZnV0dXJlLg0KVGhpcyBpcyB3aHkgSSB1c2Vk IGFsbG9jYSBpbiBwYXRjaGVzIDEvMyBhbmQgMi8zLg0KDQpJIGtub3cgdGhh dCBnY2MgYXZvaWQgdXNpbmcgc3RkOjp2ZWN0b3IgYmVjYXVzZSBpdOKAmXMg ZmFpcmx5IHNsb3cuIEkgdGhpbmsgZ2NjIGFsc28gaGF2ZSBuZXdlciBjKysg bGlrZSByZXBsYWNlbWVudHMgZm9yIFZFQywgYnV0IGFtIG5vdCBzdXJlIHdo YXQgdGhleSBoYXZlIHRoYXTigJlzIHN1aXRhYmxlLiBIb3dldmVyLCBJ4oCZ ZCBzdWdnZXN0IHRoYXTigJlzIHNvbWV0aGluZyB0aGF0IHNob3VsZCBiZSBk b25lIGFzIHBhcnQgb2YgdGhlIHdvcmsgdG8gbW92ZSBnZGIgdG8gYysrLCBh bmQgbm90IHRoaXMgcGF0Y2guDQoNCkFsYW4u >From gdb-patches-return-136127-listarch-gdb-patches=sources.redhat.com@sourceware.org Wed Jan 11 11:12:40 2017 Return-Path: Delivered-To: listarch-gdb-patches@sources.redhat.com Received: (qmail 43857 invoked by alias); 11 Jan 2017 11:12:40 -0000 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 Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 43815 invoked by uid 89); 11 Jan 2017 11:12:39 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=1.0 required=5.0 tests=AWL,BAYES_50,FREEMAIL_FROM,KAM_STOCKGEN,RCVD_IN_DNSWL_NONE,RCVD_IN_SORBS_SPAM,SPF_PASS autolearn=no version=3.3.2 spammy=H*r:AES128-SHA, predetermined, regcache.h, UD:regcache.h X-HELO: mail-wm0-f67.google.com Received: from mail-wm0-f67.google.com (HELO mail-wm0-f67.google.com) (74.125.82.67) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 11 Jan 2017 11:12:29 +0000 Received: by mail-wm0-f67.google.com with SMTP id c85so35860100wmi.1 for ; Wed, 11 Jan 2017 03:12:29 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to:user-agent; bh=jhWWaBcDEX2cjW3u0J21ACedKip/KDH88lcJpvb+KNo=; b=a35ZBfsdxFmI6NaU4zuuGKKhQIZUKrrialNiqYHtEqvzwtoxPSFAXAvS1otZ1fddA+ Ri26GUcMZG6tHN2POVy1gg4F3Ss1koejvbz+b392FWDkY+upnW+TJqXW3FupAFUmDDUh Q7JVyyFbIWhyqdGOS5JnPDtP3HKiji6ClLwjWPTusQYeM2RZbeI4YajOazZhWf7O6kgj QoWTF9QhJJAzKh4ON0CYl75A/SgD5wCHymxvQGlkMftssdmzpBB0kOV+KDEttc4ZqLQJ NMWZrEdMI3CbpMvjb31vtCJIsZRWEFCHHic0dfL6IdNnE5HD4q3ryrnmtxf/Xhmd8HRB cr2w== X-Gm-Message-State: AIkVDXLGgXLbBRlxhOndtDHAaHZ+lr26mLDBmgq3YRmG1eG7BzsuL2kaClWRqO3IZdNfHQ== X-Received: by 10.28.84.88 with SMTP id p24mr2649798wmi.52.1484133146854; Wed, 11 Jan 2017 03:12:26 -0800 (PST) Received: from E107787-LIN (gcc1-power7.osuosl.org. [140.211.15.137]) by smtp.gmail.com with ESMTPSA id f126sm29036779wme.22.2017.01.11.03.12.19 (version=TLS1_2 cipher=AES128-SHA bits=128/128); Wed, 11 Jan 2017 03:12:26 -0800 (PST) Date: Wed, 11 Jan 2017 11:12:00 -0000 From: Yao Qi To: Peter Griffin Cc: gdb-patches@sourceware.org, palves@redhat.com, brobecker@adacore.com, kevinb@redhat.com, cagney@gnu.org, dje@google.com, drow@false.org, kettenis@gnu.org, yao.qi@arm.com, stanshebs@google.com, Ulrich.Weigand@de.ibm.com, elena.zannoni@oracle.com, eliz@gnu.org, arnez@linux.vnet.ibm.com Subject: Re: [PATCH] Add Linux kernel thread runtime support. Message-ID: <20170111111210.GJ9518@E107787-LIN> References: <1482427864-4317-1-git-send-email-peter.griffin@linaro.org> <1482427864-4317-2-git-send-email-peter.griffin@linaro.org> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <1482427864-4317-2-git-send-email-peter.griffin@linaro.org> User-Agent: Mutt/1.5.21 (2010-09-15) X-IsSubscribed: yes X-SW-Source: 2017-01/txt/msg00183.txt.bz2 Content-length: 22811 On 16-12-22 17:31:04, Peter Griffin wrote: > This patch implements a new linux-kthread target_ops stratum which > supports the Linux kernel thread runtime. It allows anything > that the Linux kernel has created a task_struct for to be represented > as a GDB thread object. This allows a user using GDB to debug the > Linux kernel to see all the sleeping threads in the system rather than > just physical CPU's (as is the case currently) and then use the GDB > contextual commands such as 'thread' to easily switch between all the > threads in the system, inspect data structures and get backtraces etc. > > e.g. > (gdb) info threads > Id Target Id Frame > * 1 [swapper/0] (pid: 0 tgid: 0 ) cpu_v7_do_idle () > at /sources/linux/arch/arm/mm/proc-v7.S:75 > 2 init (pid: 1 tgid: 1) context_switch (cookie=..., > next=, prev=, rq=) > at /sources/linux/kernel/sched/core.c:2902 > 3 [kthreadd] (pid: 2 tgid: 2) context_switch (cookie=..., > next=, prev=, > rq=) at /sources/linux/kernel/sched/core.c:2902 > > 90 getty (pid: 1584 tgid: 1584) context_switch (cookie=..., > next=, prev=, > rq=) at /sources/linux/kernel/sched/core.c:2902 > 91 udevd (pid: 1586 tgid: 1586) context_switch (cookie=..., > next=, prev=, > rq=) at /sources/linux/kernel/sched/core.c:2902 Do you have some tutorials about using this feature in GDB with QEMU to debug linux kernel? I'd like to try this patch. > > linux-kthread.ch is split between the linux-kthread target_ops stratum > methods themselves which are fairly self explanatory, helper functions > which parse kernel data structures such as CPU runqueue for idle and curr > tasks and a series of low level helper functions and macros which make > obtaining symbol information and calculating struct field offsets > of the various Linux kernel data structures much easier. Looks much kernel knowledge is involved in this patch, so could you add some comments on the kernel data structures and how gdb parse them to get the list of threads? > diff --git a/gdb/arm-linux-kthread.c b/gdb/arm-linux-kthread.c > new file mode 100644 > index 0000000..a4352ac > --- /dev/null > +++ b/gdb/arm-linux-kthread.c > @@ -0,0 +1,178 @@ > +/* Linux kernel thread ARM target support. > + > + Copyright (C) 2011-2016 Free Software Foundation, Inc. > + > + This file is part of GDB. > + > + This program is free software; you can redistribute it and/or modify > + it under the terms of the GNU General Public License as published by > + the Free Software Foundation; either version 3 of the License, or > + (at your option) any later version. > + > + This program is distributed in the hope that it will be useful, > + but WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + GNU General Public License for more details. > + > + You should have received a copy of the GNU General Public License > + along with this program. If not, see . */ > + > +#include "defs.h" > +#include "gdbcore.h" > +#include "regcache.h" > +#include "inferior.h" > +#include "arch/arm.h" > +#include "arm-tdep.h" > +#include "linux-kthread.h" > +#include "arm-linux-kthread.h" > + > +/* Support for Linux kernel threads */ > + > +/* From Linux arm/include/asm/thread_info.h */ > +static struct cpu_context_save > +{ > + uint32_t r4; > + uint32_t r5; > + uint32_t r6; > + uint32_t r7; > + uint32_t r8; > + uint32_t r9; > + uint32_t sl; > + uint32_t fp; > + uint32_t sp; > + uint32_t pc; > +} cpu_cxt; > + > +/* This function gets the register values that the schedule() routine > + * has stored away on the stack to be able to restart a sleeping task. > + * > + **/ We don't write comments in this way. See https://www.gnu.org/prep/standards/standards.html#Comments > + > +static void > +arm_linuxkthread_fetch_registers (struct regcache *regcache, > + int regnum, CORE_ADDR task_struct) > +{ > + struct gdbarch *gdbarch = get_regcache_arch (regcache); > + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); > + > + CORE_ADDR sp = 0; > + gdb_byte buf[8]; > + int i; > + uint32_t cpsr; > + uint32_t thread_info_addr; > + > + DECLARE_FIELD (thread_info, cpu_context); > + DECLARE_FIELD (task_struct, stack); > + > + gdb_assert (regnum >= -1); > + > + /*get thread_info address */ > + thread_info_addr = read_unsigned_field (task_struct, task_struct, stack, > + byte_order); > + > + /*get cpu_context as saved by scheduled */ > + read_memory ((CORE_ADDR) thread_info_addr + > + F_OFFSET (thread_info, cpu_context), > + (gdb_byte *) & cpu_cxt, sizeof (struct cpu_context_save)); You are assuming the struct cpu_context_save layout is the same on both target and host, however, they can be different. The right approach, IMO, is to rely on the debug information to get the offset of each fields, and read out each field one by one. > + > + regcache_raw_supply (regcache, ARM_PC_REGNUM, &cpu_cxt.pc); > + regcache_raw_supply (regcache, ARM_SP_REGNUM, &cpu_cxt.sp); > + regcache_raw_supply (regcache, ARM_FP_REGNUM, &cpu_cxt.fp); > + > + /*general purpose registers */ > + regcache_raw_supply (regcache, 10, &cpu_cxt.sl); > + regcache_raw_supply (regcache, 9, &cpu_cxt.r9); > + regcache_raw_supply (regcache, 8, &cpu_cxt.r8); > + regcache_raw_supply (regcache, 7, &cpu_cxt.r7); > + regcache_raw_supply (regcache, 6, &cpu_cxt.r6); > + regcache_raw_supply (regcache, 5, &cpu_cxt.r5); > + regcache_raw_supply (regcache, 4, &cpu_cxt.r4); > + > + /* Fake a value for cpsr:T bit. */ > +#define IS_THUMB_ADDR(addr) ((addr) & 1) > + cpsr = IS_THUMB_ADDR(cpu_cxt.pc) ? arm_psr_thumb_bit (target_gdbarch ()) : 0; Looks you fake the cpsr value completely. GDB can't access cpsr value? > + regcache_raw_supply (regcache, ARM_PS_REGNUM, &cpsr); > + > + for (i = 0; i < gdbarch_num_regs (target_gdbarch ()); i++) > + if (REG_VALID != regcache_register_status (regcache, i)) > + /* Mark other registers as unavailable. */ > + regcache_invalidate (regcache, i); > +} > + > +static void > +arm_linuxkthread_store_registers (const struct regcache *regcache, > + int regnum, CORE_ADDR addr) > +{ > + struct gdbarch *gdbarch = get_regcache_arch (regcache); > + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); > + > + /* TODO */ > + gdb_assert (regnum >= -1); > + gdb_assert (0); It is a TODO item for your patch V2. > + > +} > + > +/* get_unmapped_area() in linux/mm/mmap.c. */ > +DECLARE_ADDR (get_unmapped_area); > + > +#define DEFAULT_PAGE_OFFSET 0xC0000000 > + > +void arm_linuxkthread_get_page_offset(CORE_ADDR *page_offset) > +{ > + const char *result = NULL; > + > + /* We can try executing a python command if it exists in the kernel > + source, and parsing the result. > + result = execute_command_to_string ("lx-pageoffset", 0); */ > + > + /* Find CONFIG_PAGE_OFFSET macro definition at get_unmapped_area symbol > + in linux/mm/mmap.c. */ > + > + result = kthread_find_macro_at_symbol(&get_unmapped_area, Space is needed before "(". Many instances around your patch. > + "CONFIG_PAGE_OFFSET"); > + if (result) > + { > + *page_offset = strtol(result, (char **) NULL, 16); > + } > + else > + { > + /* Kernel is compiled without macro info so make an educated guess. */ > + warning("Assuming PAGE_OFFSET is 0x%x. Disabling to_interrupt\n", > + DEFAULT_PAGE_OFFSET); > + /* PAGE_OFFSET can't be reliably determined so disable the target_ops > + to_interrupt ability. This means target can onbly be halted via > + a breakpoint set in the kernel, which will mean CPU is configured > + for kernel memory view. */ > + lkthread_disable_to_interrupt = 1; > + *page_offset = DEFAULT_PAGE_OFFSET; > + } > + > + return; > +} This looks very fragile to me. This function is used to determine whether PC is kernel space or not, and we only use this information to avoid interrupting the kernel when the pc is in user space. Why don't you always disable interrupt in linux-kthread target? That is a reasonable limitation to me, but the code is much clean. > +struct linux_kthread_data > +{ > + /* the processes list from Linux perspective */ > + linux_kthread_info_t *process_list = NULL; > + > + /* the process we stopped at in target_wait */ > + linux_kthread_info_t *wait_process = NULL; > + > + /* __per_cpu_offset */ > + CORE_ADDR *per_cpu_offset; > + > + /* array of cur_rq(cpu) on each cpu */ > + CORE_ADDR *rq_curr; > + > + /*array of rq->idle on each cpu */ > + CORE_ADDR *rq_idle; It would be nice that you can explain how these three fields are used. > + > + /* array of scheduled process on each core */ > + linux_kthread_info_t **running_process = NULL; std::vector running_process;? > + > + /* array of process_counts for each cpu used for process list > + housekeeping */ > + unsigned long *process_counts; > + > + /* Storage for the field layout and addresses already gathered. */ > + struct field_info *field_info_list; > + struct addr_info *addr_info_list; > + > + unsigned char *scratch_buf; > + int scratch_buf_size; > +}; > + > +/* Handle to global lkthread data. */ > +static struct linux_kthread_data *lkthread_h; > + > +/* Helper function to convert ptid to a string. */ > + > +static char * > +ptid_to_str (ptid_t ptid) > +{ > + static char str[32]; > + snprintf (str, sizeof (str) - 1, "ptid %d: lwp %ld: tid %ld", > + ptid_get_pid (ptid), ptid_get_lwp (ptid), ptid_get_tid (ptid)); > + > + return str; > +} > + > +/* Symbol and Field resolution helper functions. */ > + I don't expect seeing so much code on symbol handling in linux-kthread patch. linux-kthread just needs to query GDB symbol and type sub-system to know where a given field is in the target memory. > +/* Helper function called by ADDR macro to fetch the address of a symbol > + declared using DECLARE_ADDR macro. */ > + > +int > +lkthread_lookup_addr (struct addr_info *addr, int check) > +{ > + if (addr->bmsym.minsym) > + return 1; > + > + addr->bmsym = lookup_minimal_symbol (addr->name, NULL, NULL); > + > + if (!addr->bmsym.minsym) > + { > + if (debug_linuxkthread_symbols) > + fprintf_unfiltered (gdb_stdlog, "Checking for address of '%s' :" > + "NOT FOUND\n", addr->name); > + > + if (!check) > + error ("Couldn't find address of %s", addr->name); > + return 0; > + } > + > + /* Chain initialized entries for cleanup. */ > + addr->next = lkthread_h->addr_info_list; > + lkthread_h->addr_info_list = addr; > + > + if (debug_linuxkthread_symbols) > + fprintf_unfiltered (gdb_stdlog, "%s address is %s\n", addr->name, > + phex (BMSYMBOL_VALUE_ADDRESS (addr->bmsym), 4)); > + > + return 1; > +} > + > +/* Helper for lkthread_lookup_field. */ > + > +static int > +find_struct_field (struct type *type, char *field, int *offset, int *size) > +{ > + int i; > + > + for (i = 0; i < TYPE_NFIELDS (type); ++i) > + { > + if (!strcmp (FIELD_NAME (TYPE_FIELDS (type)[i]), field)) use TYPE_FIELD_NAME (type, i)? which is shorter. > + break; > + } > + > + if (i >= TYPE_NFIELDS (type)) > + return 0; > + > + *offset = FIELD_BITPOS (TYPE_FIELDS (type)[i]) / TARGET_CHAR_BIT; *offset = TYPE_FIELD_BITPOS (type, i) / TARGET_CHAR_BIT; > + *size = TYPE_LENGTH (check_typedef (TYPE_FIELDS (type)[i].type)); > + return 1; > +} This function can be generalized so that it can be used in other parts of GDB. /* Find the field by the name FIELD in TYPE. Return the field id if found, otherwise, return -1. */ int type_find_field (struct *type, const char *field) { int i; for (i = 0; i < TYPE_NFIELDS (type); ++i) { if (strcmp (TYPE_FIELD_NAME (type, i), field) == 0) return i; } return -1; } This function can be added to gdbtype.c and this function can be used in ada-exp.y:convert_char_literal. You can call this function to get the size and offset of a given field. > + > +/* Called by F_OFFSET or F_SIZE to compute the description of a field > + declared using DECLARE_FIELD. */ > + > +int > +lkthread_lookup_field (struct field_info *f, int check) > +{ > + > + if (f->type != NULL) > + return 1; > + > + f->type = > + lookup_symbol (f->struct_name, NULL, STRUCT_DOMAIN, NULL).symbol; > + > + if (!f->type) > + { > + f->type = lookup_symbol (f->struct_name, NULL, VAR_DOMAIN, > + NULL).symbol; > + If we are looking for a struct/union, don't have to search in VAR_DOMAIN. > + if (f->type && TYPE_CODE (check_typedef (SYMBOL_TYPE (f->type))) > + != TYPE_CODE_STRUCT) > + f->type = NULL; > + > + } > + > + if (f->type == NULL > + || !find_struct_field (check_typedef (SYMBOL_TYPE (f->type)), > + f->field_name, &f->offset, &f->size)) > + { > + f->type = NULL; > + if (!check) > + error ("No such field %s::%s\n", f->struct_name, f->field_name); > + > + return 0; > + } > + > + /* Chain initialized entries for cleanup. */ > + f->next = lkthread_h->field_info_list; > + lkthread_h->field_info_list = f; > + > + if (debug_linuxkthread_symbols) > + { > + fprintf_unfiltered (gdb_stdlog, "Checking for 'struct %s' : OK\n", > + f->struct_name); > + fprintf_unfiltered (gdb_stdlog, "%s::%s => offset %i size %i\n", > + f->struct_name, f->field_name, f->offset, f->size); > + } > + return 1; > +} > + > + > + > +/* Initialise and allocate memory for linux-kthread module. */ > + > +static void > +lkthread_init (void) > +{ > + struct thread_info *th = NULL; > + struct cleanup *cleanup; > + int size = > + TYPE_LENGTH (builtin_type (target_gdbarch ())->builtin_unsigned_long); > + > + /* Ensure thread list from beneath target is up to date. */ > + cleanup = make_cleanup_restore_integer (&print_thread_events); > + print_thread_events = 0; > + update_thread_list (); > + do_cleanups (cleanup); > + > + /* Count the h/w threads. */ > + max_cores = thread_count (); I am confused by this line. Could you explain? > + gdb_assert (max_cores); > + > + if (debug_linuxkthread_threads) > + { > + fprintf_unfiltered (gdb_stdlog, "lkthread_init() cores(%d) GDB" > + "HW threads\n", max_cores); > + iterate_over_threads (thread_print_info, NULL); > + } > + > + /* Allocate per cpu data. */ > + lkthread_alloc_percpu_data(max_cores); > + > + lkthread_get_per_cpu_offsets(max_cores); Why do we need to model per_cpu data in GDB side? I assume kernel has a global list of all tasks/threads, and GDB can read the element one by one from that list, and create a list of threads in its side. > diff --git a/gdb/linux-kthread.h b/gdb/linux-kthread.h > new file mode 100644 > index 0000000..cffa0f4 > --- /dev/null > +++ b/gdb/linux-kthread.h > @@ -0,0 +1,223 @@ > +/* Linux kernel-level threads support. > + > + Copyright (C) 2016 Free Software Foundation, Inc. > + > + This file is part of GDB. > + > + This program is free software; you can redistribute it and/or modify > + it under the terms of the GNU General Public License as published by > + the Free Software Foundation; either version 3 of the License, or > + (at your option) any later version. > + > + This program is distributed in the hope that it will be useful, > + but WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + GNU General Public License for more details. > + > + You should have received a copy of the GNU General Public License > + along with this program. If not, see . */ > + > +#ifndef LINUX_KTHREAD_H > +#define LINUX_KTHREAD_H 1 > + > +#include "objfiles.h" > + > +struct addr_info > +{ > + char *name; > + struct bound_minimal_symbol bmsym; Why do you use bound_minimal_symbol instead of minimal_symbol? bound_minimal_symbol.objfile is not interesting here. > + /* Chained to allow easy cleanup. */ > + struct addr_info *next; > +}; IIUC, each entry represent an global variable in kernel, so it is better to be named as "variable" or "variable_info". Secondly, the struct addr_info don't need to be a list. It can be an array since all the variables GDB wants to know in kernel is pre-determined. We can have an array, std::arrayvariables, and manually allocate index to each global variable in kernel. > + > +struct field_info > +{ > + char *struct_name; > + char *field_name; > + struct symbol *type; s/struct symbol/struct type/ because we need the type of the struct instead of the symbol. > + int offset; > + int size; > + /* Chained to allow easy cleanup. */ > + struct field_info *next; > +}; Don't need to record much information here, we only need the type of the struct and its field id in the type. struct field_info can be put into an array instead of list, because all the structs and fields GDB wants to access is pre-determined. /* A field F in struct is represented as the struct below. */ struct field_info { /* The type of struct S. */ struct type* s; /* F's field id in struct S. */ int field_id; }; and you can allocated index for each struct and field combination. enum field_index { FIELD_INFO (thread_info, cpu_context), FIELD_INFO (task_struct, stack), FIELD_INFO (task_struct, active_mm), ... field_index_last, } std::array fields; and access the field_info array like this, fields[FIELD_INFO (task_struct, stack)] = xxxx initialize the elements in array fields to get the type and field id of each field. Then, you can easily get the size and offset of field by TYPE and FIELD_ID. > + > + > +/* The list of Linux threads cached by linux-kthread. */ > +typedef struct private_thread_info > +{ > + struct private_thread_info *next; > + CORE_ADDR task_struct; > + CORE_ADDR mm; > + CORE_ADDR active_mm; > + > + ptid_t old_ptid; > + > + /* This is the "dynamic" core info. */ > + int core; > + > + int tgid; > + unsigned int prio; > + char *comm; > + int valid; > + > + struct thread_info *gdb_thread; > +} linux_kthread_info_t; > + > +#define PTID_OF(ps) ((ps)->gdb_thread->ptid) > + > +int lkthread_lookup_addr (struct addr_info *field, int check); > +int lkthread_lookup_field (struct field_info *field, int check); > + > +static inline CORE_ADDR > +lkthread_get_address (struct addr_info *addr) > +{ > + if (addr->bmsym.minsym == NULL) > + lkthread_lookup_addr (addr, 0); > + > + return BMSYMBOL_VALUE_ADDRESS (addr->bmsym); > +} > + > +static inline unsigned int > +lkthread_get_field_offset (struct field_info *field) > +{ > + if (field->type == NULL) > + lkthread_lookup_field (field, 0); > + > + return field->offset; > +} > + > +static inline unsigned int > +lkthread_get_field_size (struct field_info *field) > +{ > + if (field->type == NULL) > + lkthread_lookup_field (field, 0); > + > + return field->size; > +} > + > +#define CORE_INVAL (-1) > + > +#define FIELD_INFO(s_name, field) _FIELD_##s_name##__##field > + > +#define DECLARE_FIELD(s_name, field) \ > + static struct field_info FIELD_INFO(s_name, field) \ > + = { .struct_name = #s_name, .field_name = #field, 0 } > + > +#define F_OFFSET(struct, field) \ > + lkthread_get_field_offset (&FIELD_INFO(struct, field)) > + > +#define F_SIZE(struct, field) \ > + lkthread_get_field_size (&FIELD_INFO(struct, field)) > + > +#define HAS_FIELD(struct, field) \ > + (FIELD_INFO(struct, field).type != NULL \ > + || (lkthread_lookup_field(&FIELD_INFO(struct, field), 1), \ > + FIELD_INFO(struct, field).type != NULL)) > + > +#define DECLARE_ADDR(symb) \ > + static struct addr_info symb = { .name = #symb, .bmsym = {NULL, NULL} } > + > +#define HAS_ADDR(symb) \ > + (symb.bmsym.minsym != NULL \ > + || (lkthread_lookup_addr(&symb, 1), symb.bmsym.minsym != NULL)) > + > +#define HAS_ADDR_PTR(symb) \ > + (symb->bmsym.minsym != NULL \ > + || (lkthread_lookup_addr(symb, 1), symb->bmsym.minsym != NULL)) > + > +#define ADDR(sym) lkthread_get_address (&sym) > + > +#define ADDR_PTR(sym) lkthread_get_address (sym) > + > +#define read_unsigned_field(base, struct, field, byteorder) \ > + read_memory_unsigned_integer (base + F_OFFSET (struct, field), \ > + F_SIZE (struct, field), byteorder) > + > +#define read_signed_field(base, struct, field, byteorder) \ > + read_memory_integer (base + F_OFFSET (struct, field), \ > + F_SIZE (struct, field), byteorder) > + > +#define read_pointer_field(base, struct, field) \ > + read_memory_typed_address (base + F_OFFSET (struct, field), \ > + builtin_type (target_gdbarch ())->builtin_data_ptr) > + > +#define read_unsigned_embedded_field(base, struct, field, emb_str, \ > + emb_field, byteorder) \ > + read_memory_unsigned_integer (base + F_OFFSET (struct, field) \ > + + F_OFFSET (emb_str, emb_field), \ > + F_SIZE (emb_str, emb_field), byteorder) > + > +#define read_signed_embedded_field(base, struct, field, emb_str, \ > + emb_field, byteorder) \ > + read_memory_integer (base + F_OFFSET (struct, field) \ > + + F_OFFSET (emb_str, emb_field), \ > + F_SIZE (emb_str, emb_field), byteorder) > + > +#define read_pointer_embedded_field(base, struct, field, emb_str, \ > + emb_field) \ > + read_memory_typed_address (base + F_OFFSET (struct, field) \ > + + F_OFFSET (emb_str, emb_field), \ > + builtin_type (target_gdbarch ())->builtin_data_ptr) > + > +#define extract_unsigned_field(base, struct, field, byteorder) \ > + extract_unsigned_integer(base + F_OFFSET (struct, field), \ > + F_SIZE (struct, field), byteorder) > + > +#define extract_signed_field(base, struct, field, byteorder) \ > + extract_signed_integer (base + F_OFFSET (struct, field), \ > + F_SIZE (struct, field), byteorder) > + > +#define extract_pointer_field(base, struct, field) \ > + extract_typed_address (base + F_OFFSET (struct, field), \ > + builtin_type(target_gdbarch ())->builtin_data_ptr) > + > +/* Mimic kernel macros. */ > +#define container_of(ptr, struc, field) ((ptr) - F_OFFSET(struc, field)) > + > + > +/* Mapping GDB PTID to Linux PID and Core > + > + GDB Remote uses LWP to store the effective cpu core Why? > + ptid.pid = Inferior PID > + ptid.lwp = CPU Core > + ptid.tid = 0 > + > + We store Linux PID in TID. */ Why don't you implement target_ops to_core_of_thread? -- Yao