gdb如何比较core文件和image及buildid

gdb

从git上看到的提交记录,关键的修改是在elf_core_file_matches_executable_p函数中添加的对于build_id的比较。

///@file: gdb-10.1\bfd\elfcore.h
bfd_boolean
elf_core_file_matches_executable_p (bfd *core_bfd, bfd *exec_bfd)
{
  char* corename;

  /* xvecs must match if both are ELF files for the same target.  */

  if (core_bfd->xvec != exec_bfd->xvec)
    {
      bfd_set_error (bfd_error_system_call);
      return FALSE;
    }

  /* If both BFDs have identical build-ids, then they match.  */
  if (core_bfd->build_id != NULL
      && exec_bfd->build_id != NULL
      && core_bfd->build_id->size == exec_bfd->build_id->size
      && memcmp (core_bfd->build_id->data, exec_bfd->build_id->data,
		 core_bfd->build_id->size) == 0)
    return TRUE;

  /* See if the name in the corefile matches the executable name.  */
  corename = elf_tdata (core_bfd)->core->program;
  if (corename != NULL)
    {
      const char* execname = strrchr (bfd_get_filename (exec_bfd), '/');

      execname = execname ? execname + 1 : bfd_get_filename (exec_bfd);

      if (strcmp (execname, corename) != 0)
	return FALSE;
    }

  return TRUE;
}

buildid

直观上看,这个信息应该是由内核在生成coredump文件的时候生成的,但是在内核的代码中并没有找到对于这个buildid的特殊处理(关键字是NT_GNU_BUILD_ID)。好在结合本次提交信息可以很快找到对应的实现:就是从coredump文件中包含的文件映射信息中读取的,读取的方法也是遍历文件header中的所有note信息,然后找到其中包含NT_GNU_BUILD_ID的节。由于这份数据是在生成coredump文件的时候从内存中生成的一个拷贝,所以可以具有记录信息。

static bfd_boolean
elfobj_grok_gnu_note (bfd *abfd, Elf_Internal_Note *note)
{
  switch (note->type)
    {
    default:
      return TRUE;

    case NT_GNU_PROPERTY_TYPE_0:
      return _bfd_elf_parse_gnu_properties (abfd, note);

    case NT_GNU_BUILD_ID:
      return elfobj_grok_gnu_build_id (abfd, note);
    }
}
static bfd_boolean
elf_parse_notes (bfd *abfd, char *buf, size_t size, file_ptr offset,
		 size_t align)
{
///...
	case bfd_core:
	  {
#define GROKER_ELEMENT(S,F) {S, sizeof (S) - 1, F}
	    struct
	    {
	      const char * string;
	      size_t len;
	      bfd_boolean (* func)(bfd *, Elf_Internal_Note *);
	    }
	    grokers[] =
	    {
	      GROKER_ELEMENT ("", elfcore_grok_note),
	      GROKER_ELEMENT ("FreeBSD", elfcore_grok_freebsd_note),
	      GROKER_ELEMENT ("NetBSD-CORE", elfcore_grok_netbsd_note),
	      GROKER_ELEMENT ( "OpenBSD", elfcore_grok_openbsd_note),
	      GROKER_ELEMENT ("QNX", elfcore_grok_nto_note),
	      GROKER_ELEMENT ("SPU/", elfcore_grok_spu_note),
	      GROKER_ELEMENT ("GNU", elfobj_grok_gnu_note)
	    };
#undef GROKER_ELEMENT
	    int i;

	    for (i = ARRAY_SIZE (grokers); i--;)
	      {
		if (in.namesz >= grokers[i].len
		    && strncmp (in.namedata, grokers[i].string,
				grokers[i].len) == 0)
		  {
		    if (! grokers[i].func (abfd, & in))
		      return FALSE;
		    break;
		  }
	      }
	    break;
	  }
///...
}

在linux下,可以通过readelf命令查看可执行文件的BUILD_ID,

tsecer@harry: readelf -n a.out  

Displaying notes found at file offset 0x00000274 with length 0x00000024:
  所有者             Data size  Description
  GNU                  0x00000014       NT_GNU_BUILD_ID (unique build ID bitstring)
    Build ID: 296dc8433375f102ba8f0e3b766fec0cb12cc170

note

从内核填充note的代码可以看到,note首先是通过字符串表示属于哪个大的范围,之后还有一个数值表示属于哪个小类,最后通过长度+内容表示文件内容

static void fill_note(struct memelfnote *note, const char *name, int type, 
		unsigned int sz, void *data)
{
	note->name = name;
	note->type = type;
	note->datasz = sz;
	note->data = data;
	return;
}

结合gdb的代码可以看到,GNU扩展的note为一类,该类中当前包含了一些信息,其中就包含了我们关心的NT_GNU_BUILD_ID字段

/* Values for notes in non-core files using name "GNU".  */

#define NT_GNU_ABI_TAG		1
#define NT_GNU_HWCAP		2	/* Used by ld.so and kernel vDSO.  */
#define NT_GNU_BUILD_ID		3	/* Generated by ld --build-id.  */
#define NT_GNU_GOLD_VERSION	4	/* Generated by gold.  */
#define NT_GNU_PROPERTY_TYPE_0  5	/* Generated by gcc.  */

#define NT_GNU_BUILD_ATTRIBUTE_OPEN	0x100
#define NT_GNU_BUILD_ATTRIBUTE_FUNC	0x101

perf

从perf的调用链可以看到,在perf的session结束之后,还是会记录所有buildid信息,并且还会缓存文件。

(gdb) bt
#0  write_buildid (fd=3, misc=1, pid=-1, build_id=0x7f1ddb "\026ٸ\351\264\325\062\223\330\001t谢k\341˾Ω", name_len=18, name=<optimized out>) at util/header.c:223
#1  __dsos__write_buildid_table (head=head@entry=0x7f1b18, pid=-1, misc=1, fd=fd@entry=3) at util/header.c:255
#2  0x00000000004738db in machine__write_buildid_table (fd=3, machine=0x7f1ac0) at util/header.c:275
#3  dsos__write_buildid_table (fd=3, header=0x7f19d0) at util/header.c:288
#4  write_build_id (fd=fd@entry=3, h=h@entry=0x7f19d0, evlist=evlist@entry=0x7f0d40) at util/header.c:497
#5  0x0000000000474612 in do_write_feat (evlist=0x7f0d40, p=<synthetic pointer>, type=2, h=0x7f19d0, fd=3) at util/header.c:2225
#6  perf_header__adds_write (fd=3, evlist=0x7f0d40, header=0x7f19d0) at util/header.c:2264
#7  perf_session__write_header (session=0x7f19d0, evlist=0x7f0d40, fd=3, at_exit=at_exit@entry=true) at util/header.c:2361
#8  0x000000000042cd8a in perf_record__exit (status=<optimized out>, arg=0x71ab00 <record>) at builtin-record.c:317
#9  0x00007ffff5b21a49 in __run_exit_handlers () from /lib64/libc.so.6
#10 0x00007ffff5b21ab5 in exit () from /lib64/libc.so.6
#11 0x0000000000416760 in handle_internal_command (argv=0x7fffffffe380, argc=4) at perf.c:376
#12 run_argv (argv=0x7fffffffe180, argcp=0x7fffffffe18c) at perf.c:420
#13 main (argc=4, argv=0x7fffffffe380) at perf.c:521
(gdb) 
static int perf_session__cache_build_ids(struct perf_session *session)
{
	struct rb_node *nd;
	int ret;
	char debugdir[PATH_MAX];

	snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir);

	if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
		return -1;

	ret = machine__cache_build_ids(&session->machines.host, debugdir);

	for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
		struct machine *pos = rb_entry(nd, struct machine, rb_node);
		ret |= machine__cache_build_ids(pos, debugdir);
	}
	return ret ? -1 : 0;
}

int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
			  const char *name, bool is_kallsyms, bool is_vdso)
{
///...
	len = scnprintf(filename, size, "%s%s%s",
		       debugdir, slash ? "/" : "",
		       is_vdso ? VDSO__MAP_NAME : realname);
	if (mkdir_p(filename, 0755))
		goto out_free;

	snprintf(filename + len, size - len, "/%s", sbuild_id);

	if (access(filename, F_OK)) {
		if (is_kallsyms) {
			 if (copyfile("/proc/kallsyms", filename))
				goto out_free;
		} else if (link(realname, filename) && copyfile(name, filename))
			goto out_free;
	}

	len = scnprintf(linkname, size, "%s/.build-id/%.2s",
		       debugdir, sbuild_id);
///...
}

perf为什么要保存这些二进制呢?在perf的一个wiki文档中的一个说明可能有一定意义:也就是为了在系统中保存多个同名文件的备份,这样文件被重新编译之后,还可以使用perf数据生成时使用的二进制文件。

Given that build-id are immutable, they uniquely identify a binary. If a binary is recompiled, a new build-id is generated and a new copy of the ELF images is saved in the cache. 

在查找符号的过程中,是按照这个顺序逐个尝试的,并且后面尝试成功将会覆盖前面尝试成功的内容,或者说:越靠后的位置读取到的文件优先级越高

static enum dso_binary_type binary_type_symtab[] = {
	DSO_BINARY_TYPE__KALLSYMS,
	DSO_BINARY_TYPE__GUEST_KALLSYMS,
	DSO_BINARY_TYPE__JAVA_JIT,
	DSO_BINARY_TYPE__DEBUGLINK,
	DSO_BINARY_TYPE__BUILD_ID_CACHE,
	DSO_BINARY_TYPE__FEDORA_DEBUGINFO,
	DSO_BINARY_TYPE__UBUNTU_DEBUGINFO,
	DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
	DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
	DSO_BINARY_TYPE__GUEST_KMODULE,
	DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
	DSO_BINARY_TYPE__NOT_FOUND,
};
int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
{
///...
	/* Iterate over candidate debug images.
	 * Keep track of "interesting" ones (those which have a symtab, dynsym,
	 * and/or opd section) for processing.
	 */
	for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) {
		struct symsrc *ss = &ss_[ss_pos];
		bool next_slot = false;

		enum dso_binary_type symtab_type = binary_type_symtab[i];

		if (dso__binary_type_file(dso, symtab_type,
					  root_dir, name, PATH_MAX))
			continue;
///...
}

补充

gdb比较buildid的修改在2019-10-30 Keith Seitz 提交,通过gdb的发布历史,可以看到在此次提交之后最近的一次发布是gdb的9.1版本。

Release Estimate Schedule Actual Slip (months) Comment
9.1 2019-12 2019-12 2020-02-08 1.5 Large number of issues to investigate
8.3.1 2019-08 2019-09 2019-09-20 0.5 None

本文转载于网络 如有侵权请联系删除

相关文章

  • SAP UI5 初学者教程之七 - JSON 模型初探

    本教程的第四个步骤,我们学习了SAPUI5MVC架构中的V:XML视图:SAPUI5初学者教程之四:XML视图初探第五个教程,我们学习了MVC中的C:Controller即控制器:SAPUI5初学者教程之五:视图控制器初探本步骤,我们将以JSON模型为例,学习SAPUI5MVC剩下的M-Model,模型层的设计。先看按照这个步骤完成的SAPUI5应用的效果:http://localhost:8080/webapp/index.html这个应用里我们看见了两个控件,分别是:SayHello按钮控件值为World,描述信息为HelloWorld的Input控件本步骤的全部源代码,位于我Github这个代码仓库的07文件夹之下:https://github.com/wangzixi-diablo/ui5-tutor

  • 精通Excel数组公式025:LINEST数组函数

    学习Excel技术,关注微信公众号:excelperfect如果正在进行与x-y直线数据集相关的统计计算,那么一定会喜欢LINEST函数。当使用最小二乘法将数据拟合到一条直线时,LINEST函数可以进行许多统计计算。下面列出了该函数可以进行的一些统计计算:1.判定系数2.自由度3.F统计4.截距5.斜率6.截距的标准差7.斜率的标准差8.y标准差9.回归平方和10.残差平方和使用LINEST将斜率和截距传递到水平单元格区域如下图1所示,由于要使用数组函数LINEST传递两个值,步骤如下:1.选择单元格D2:E2。2.为LINEST函数的第1个参数指定y值,即学生最终的分数所在的区域B2:B12。3.为LINEST函数的第2个参数指定x值,即学生为准备测试学习的时间所在的区域A2:A12。4.忽略参数const,此时默认TRUE,正常计算截距。5.忽略参数stats,此时默认FALSE,只计算斜率和截距。6.使用Ctrl+Shift+Enter键输入公式。图1如果要将计算出的斜率和截距传递到垂直区域,则使用图1中右下方的公式。使用LINEST传递一个x变量的10个统计数据本示例展示如何显

  • 十几分钟写个实时协作表格

    最近在使用jexcel,所以顺便尝试下写个简单的协作表格 源码地址:klren0312/realtimeExcel:ws+jexcel,createsimplerealtimeexcel(github.com) aaa.gif一.原理使用jexcel的api监听表格的修改,将修改的相关数据通过websocket传给后台,后台再将数据广播给其他websocket客户端,客户端接收到修改后修改表格二.websocket数据格式1.心跳{ type:'checkalive' }复制2.获取当前全部数据客户端发送请求{ type:'new' }复制服务端发送全部数据{ type:'history', has:true, data:[] }复制3.表格修改{ type:'excelChange', data:{ x:'',//x坐标 y:'',//y坐标 value:''//数据 }, total:[]//全部数据,用于后台缓存全部数据 }复制5.excel

  • 人体姿势估计神经网络概述– HRNet + HigherHRNet,体系结构和常见问题解答

    高分辨率网络(HRNet)是用于人体姿势估计的先进神经网络-一种图像处理任务,可在图像中找到对象的关节和身体部位的配置。网络中的新颖之处在于保持输入数据的高分辨率表示,并将其与高分辨率到低分辨率子网并行组合,同时保持有效的计算复杂性和参数计数。https://arxiv.org/pdf/1902.09212.pdf在这篇文章中,将介绍:为什么选择HRNet?HRNet与架构HigherHRNet:用于自下而上的人体姿势估计的规模感知表示学习示范影片代码常见问题解答为什么选择HRNet?良好的文档记录和维护的开源(链接)。github上有2490颗星–在所有人体姿态估计中评分最高。https://github.com/leoxiaobin/deep-high-resolution-net.pytorch它被用作同一研究空间中最新新架构的中坚力量(项目示例)https://jingdongwang2017.github.io/Projects/HRNet/PoseEstimation.html在许多姿势估计挑战中的顶级竞争对手(参考):https://paperswithcode.com/

  • 中国有微信和支付宝, 你为啥还费力不讨好去做区块链? | 人物志

    记者|佩奇出品|区块链大本营(blockchain_camp) 微信、支付宝都是特别大的节点,大家都相信它,你为什么还用区块链?它已经足够方便、足够高效了。他是一位连续创业者,曾在当时互联网最大二级市场票务平台悠闲地“打工”,生活无忧无虑无所求。一次偶然的机会,他“勾搭”上了一位澳洲技术男,异地畅聊、跨国面基之后,一头扎进了区块链行业,从此一发不可收。“你竟然秒回?”“你难道都不需要休息吗?”“你已经人不人鬼不鬼了!”这就是家人、朋友对他的评价,可以说几乎是一边倒。因为对区块链的热爱,他摒弃了之前超级balance的生活与工作,彻彻底底成为了一位工作狂。 他认为,如果区块链行业走向成熟需要迈出100步,那么这十年的历史仅仅是0.1步。尤其是在中国,微信、支付宝给予了中国用户如此好的用户体验,借用区块链技术去颠覆这些巨头,几乎不可能。 他就是AlphaWalletCEO张中南,是区块链开发者应该有的样子。为什么未来需要一个token化的世界,token化的世界究竟是怎样的?中国开发者既聪明又功利?Libra理想很美好,现实很骨感?近期,营长对这位不分日夜的加班狂人进行了专访。让我们从他的

  • iconfont的使用

    1.font-class引用 备注:不支持多色 <linkrel="stylesheet"type="text/css"href="../../SL%20img/one/iconfont.css"> <!--引入矢量图路劲--> </head> <body> <div> <iclass="iconfonticon-kefu"></i> <iclass="iconfonticon-bofang"></i> <iclass="iconfonticon-shenfenzheng"></i> <!--这个为引入的矢量图及各个图标的名字路径--> </div> </body> </html> <!--第一步:在阿里矢量图找到需要的图标并添加到购物车--> <!--第二步:下载代码并

  • 大数据计数原理1+0=1这你都不会算(一)No.47

    hello哈,大家是不是好久没见到我啦?我也是一直在摸索小伙伴们喜欢看到什么东西,不喜欢看什么东西,还请大家多多支持。为了表示感谢。小蕉在这给你们一鞠躬,二鞠躬,三。事不过三~1+0=1你都不会谈什么大数据?这篇呢,又是开坑之作,这是一个系列,主要会将大数据下的计数原理。说到计数,不知道大家会第一印象想到什么,我估计会是。。数手指。。没错,小蕉从小学开始就开始数手指,所有20以内的加减法很早就掌握了。研表究明,这估计也是我们现在使用十进制的原因,如果我们每个人每只手都有6只手指,那我们可能就用十二进制了。好了不扯了,那用程序怎么计数呢?要去重那种。按照我拍脑袋设想呢,第一印象,嗯用HastSet准没错,但是HashSet占用的内存有多少你们知道吗?可以装下我一年的米饭。内存占用太大,所以就有了后面的B-tree,Bitmap,BloomFilter,LinearCounting,LogLogCounting,AdaptiveCounting,HyperLogLogCounting,HyperLogLog++Counting。如果现在你们一个都听不懂的话,那就对了,但那也木有关系,我会一

  • java.nio包的分析(一)--Buffer类

        继上次草草的分析完Java.nio.current的分析,个人感觉还是收获非常大的。虽说不能理解全部,但是绝对比以前的感觉好很多。趁着这股热劲,最近开始研究Java.nio下的源码,Java.nio,也许也是非常少的人听过吧,在Java的基础书里面一般也不会提及到的,我记得网上好像有2中说法,一种Nio为newI/O的简写还有一种是Nio为NonBoclk I/O的意思。非阻塞I/O。下面给出百度百科上的解释。    好的,下面来说一下,nio下的包的目录结构,总体来说,Nio算的上Java后来添加的一项高级属性了吧。 目录很清晰,通过目录名称也基本知道他的一些主要的功能分类,下面从上往下开始逐步的研究它的源代码,Java.nio下面直接的类为一堆的Buffer缓冲类,后面的各种Channel都是基于Buffer类进行操作的。 首先我们当然得先了解里面最最原始的类,Buffer的构成,才能明白后面衍生出的各种基本裂隙对于的Buffer类 Buffer类的后续操作都是基于这几个值进行操作的,不

  • docker开发常用命令

    18742018-06-1916:57:41rootyuminstalldocker 18752018-06-1917:05:50rootdocker--version 18762018-06-1917:05:55rootdockerversion 18772018-06-1917:06:10rootservicedockerstart 18782018-06-1917:06:13rootdockerversion 18792018-06-1917:07:11rootsystemctlenabledocker.service 18802018-06-1917:07:52rootdockerpullcentos 18812018-06-1917:09:05rootls 18822018-06-1917:09:11rootdockerimages 18832018-06-1918:22:24rootls 18842018-06-1919:00:57rootdockerimages 18852018-06-1919:00:58rootls 18862018-06-1919:01:10root

  • @Value注入map、List,yaml格式

    使用@Value注入map、List 实体类 @Value("#{'${list}'.split(',')}") privateList<String>list; @Value("#{${maps}}") privateMap<String,String>maps; 复制    配置文件 list:topic1,topic2,topic3 maps:"{key1:'value1',key2:'value2'}" 复制    ps:注意上面的map解析中,一定要用""把map所对应的value包起来,要不然解析会失败,导致不能转成Map<String,String>。 https://github.com/godmaybelieve

  • 读书笔记-《网络是怎样连接的》笔记2 第一章

    目录1.1生成HTTP请求消息1.1.1探索之旅从输入网址开始1.1.2浏览器先要解析URL1.1.3省略文件名的情况1.1.4HTTP的基本思路1.1.5生成HTTP请求消息1.1.6发送请求后会收到响应1.2向DNS服务器查询Web服务器的IP地址1.2.1IP地址的基本知识1.2.2域名和IP地址并用的理由1.2.3Socket库提供查询IP地址的功能1.2.4通过解析器向DNS服务器发出查询1.2.5解析器的内部原理1.3全世界DNS服务器的大接力1.3.1DNS服务器的基本工作1.3.2域名的层次结构1.3.3寻找相应的DNS服务器并获取IP地址1.3.4通过缓存加快DNS服务器的响应1.4委托协议栈发送消息1.4.1数据收发操作概览1.4.2创建套接字阶段(图1.18①)1.4.3连接阶段:把管道接上去(图1.18②)1.4.4通信阶段:传递消息(图1.18③)1.4.5断开阶段:收发数据结束 1.1生成HTTP请求消息 用户在浏览器中输入网址后,浏览器对网址进行解析,根据网址的含义来生成请求消息。浏览器通过请求消息将用户需要哪些数据告知服务器。 浏览器如何解析网址 请求

  • contest hunter 5104 I-country

    #include<cstdio> #include<cstring> #include<iostream> #define_ff[i][j][l][r][x][y] #define_clcl[i][j][l][r][x][y] #define_crcr[i][j][l][r][x][y] #define_dxdx[i][j][l][r][x][y] #define_dydy[i][j][l][r][x][y] usingnamespacestd; constintN=16,K=226; intn,m,k,f[N][K][N][N][2][2],a[N][N],b[N][N]; intcl[N][K][N][N][2][2],cr[N][K][N][N][2][2]; intdx[N][K][N][N][2][2],dy[N][K][N][N][2][2]; inlinevoidwork(inti,intj,intl,intr,intx,inty,intw,intL,intR,intX,intY){ if(w<_f)return; _f=w;

  • 本地搭建SVN服务器(Windows环境)

         SVN是一款很好用的开源版本管理软件。它可以记住每一次的文件变动,可以将项目或者文档恢复到旧的版本。即使没有服务器,也可以在本地搭建SVN服务器,而且非常方便。下面就来看下如何在本地搭建SVN服务器。 一、下载及安装对应软件   平时作为客户端,我们使用的是TortoiseSVN(官方下载地址),也就是俗称的小乌龟。如果要搭建SVN服务器,需要下载VisualSVNServer(官方下载地址)。下载VisualSVNServer后进行安装。安装中途会需要填路径,其中: Location:为安装目录 Repositories:为版本库目录 PS:建议两个路径中间均不要有空格,不然使用一些命令时容易有问题。   二、创建版本库 1、打开刚安装的VisualSVNserverManger,右键Repositories→新建→Repository...,输入一个版本库名称,创建一个版本库,如下。   2、可默认创建空的版本库,也可以创建带trunk、branches、tags三个子文件夹的版本库。其实只是提供一种便利,跟创建完空的版本库,再自己手动建三个子文件夹

  • FY-4A批量几何校正(基于GDAL)

    引言 ​ 前次介绍了FY-4A遥感影像的几何校正方法,然而其主体基于ENVI实现,虽然可以通过ENVI_DO_IT和IDL语言实现批量化处理,但由于ENVI中GLT的生成需要经纬度查找表没有无效值,需要裁剪,所以比较麻烦。 ​ 下面介绍一下基于gdal进行FY-4A几何校正的方法。仔细阅读李民录老师《gdal实现静止卫星几何校正》相关文章后,发现其主要流程都是先gdalinfo查看数据集,再gdaltranslate生成vrt,然后修改vrt添加查找表数据路径,最后gdalwarp进行几何校正。 ​ 实施过程中也发现了一些问题,如圆盘数据的类型不同,有HDF/NC/Tiff,存储方式不同,读取时文件的路径也各不相同,有的文件类型如NC甚至无法生成VRT文件。综合分析后,笔者决定拆解这一问题,既然gdalwarp的核心是根据影像数组,经纬度查找表数组进行几何校正,那就可以只凭借这三个数组实现几何校正,故可以生产各自的geotiff文件,略去多余的信息。 步骤 数据准备 1.1遥感影像nc转geotiff ​ FY-4A遥感影像属于netCDF数据集,在使用gdal_translate

  • BindingException: Mapper method &#39;xxx.dao.StudentDao.insertStudent&#39; attempted to return null from a method with a primitive return type (int).

    一、问题 报错结果:  二、造成错误代码 本人造成的错误是在dao/StudentDao.xml文件造成的,也就是持久层的dao配置文件写错了,下面是本人的错误代码: <selectid="insertStudent"> insertintostudent1(name,age)values(#{name},#{age}) </select>复制 造成错误的原因,这是新手容易犯的错误,将插入数据标签写成查询数据的标签,导致错误  三、解决方法 正确代码 <insertid="insertStudent"> insertintostudent1(name,age)values(#{name},#{age}) </insert>复制  

  • 可行性的膜渗透性计算:纯脂质双层膜和哺乳动物细胞膜对短链醇的渗透性研究

    青青河畔草,郁郁园中柳。 盈盈楼上女,皎皎当窗牖。 娥娥红粉妆,纤纤出素手。 昔为倡家女,今为荡子妇。 荡子行不归,空床难独守。 说这么几句定场诗,起到解乏的作用(笑)。很久没有看过自然科学相关的文章了,遂记下此篇。阅读文章时的疑惑与试解也一并录入,以便日后翻阅。倘若能助君一二,乃小生之荣幸。如意转载,请君自便。 Affordablemembranepermeabilitycalculations:Permeationofshort-chainalcoholsthroughpure-lipidbilayersandamammaliancellmembrane 可行性的膜渗透性计算:纯脂质双层膜和哺乳动物细胞膜对短链醇的渗透性研究 纯脂质双层膜 图一,脂质双层膜示意图,[图源](https://en.wikipedia.org/wiki/Lipid_bilayer) 目录 摘要 摘要 从第一型原理出发计算膜结构对小分子的渗透能力为先导化合物的渗透特性计算提供了一种解决方法,该方法可以被应用于药物发现和药物合成之中。渗透事件的模拟计算需要用到膜结构的分子模型,分子模型的选择不仅会

  • svn

     1、svn 检出命令:checkout(co)svn checkout https://192.168.1.91/svn/xg_new/xg/ --username=mj --password=123 /Usersentong/Desktop说明:将服务器中xg仓库的内容下载到/Usersentong/Desktop目录中。不指定本地目录全路径,则检出到当前目录下。遇到个问题,就是用户验证提示,第一次遇到没认真看英语,还以为失败了,仔细翻译了下才知道,是询问是否接受凭证的,对应输入永久接受凭证的字母即可。2、svn 导出命令:exportsvn update [-r 版本号] https:xxx [导出位置:本地全路径] --usernamesvn update 本地版本全路径 导出位置:本地全路径说明:导出版本,加-r指定版本号,否则默认最新的;第二种则是从本地版本导出。3、svn 更新命令:update

  • Android Healthd Framework(三)Charge

    整理中

  • .Net Core 管道中的ConfigureServices 和Configure

    ConfigureServices  就是配置服务器的DI容器 把需要的中间件等一些东西添加到DI容器  最后都是添加到IServiceCollection里面 比如 services.AddIdentityServer() .AddDeveloperSigningCredential() .AddInMemoryApiResources(Config.GetResource()) .AddInMemoryClients(Config.GetClients()) .AddTestUsers(Config.GetTestUsers()) .AddProfileService<ProfileService>() .AddResourceOwnerValidator<LoginValidator>();复制 对于.AddProfileService()   已经内置了一个默认实现IProfileService接口的一个类  默认会注入内置的(DefaultProfileSer

  • 第七周周记

    学习进度表 周数 专业学习目标 专业学习时间 新增代码量 博客发表量 人文方面的学习 知识技能总结  第七周 html 每天晚上七点到八点。 试着写记忆翻牌小游戏的代码 已发  css 弄懂英语单词是什么意思就行   要弄懂代码每一行的意思就可以举一反三。

  • Equals与GetHashcode

    一.两个逻辑上相等的实例对象。 两个对象相等,除了指两个不同变量引用了同一个对象外,更多的是指逻辑上的相等。什么是逻辑上相等呢?就是在一定的前提上,这两个对象是相等的。比如说某男生叫刘益红,然后也有另外一个女生叫刘益红,虽然这两个人身高,爱好,甚至性别上都不相同,但是从名字上来说,两者是相同的。Equals方法通常指的就是逻辑上相等。 二.Object的GetHashcode方法。 计算Hashcode的算法中,应该至少包含一个实例字段。Object中由于没有有意义的实例字段,也对其派生类型的字段一无所知,因此就没有逻辑相等这一概念。所以默认情况下Object的GetHashcode方法的返回值,应该都是独一无二的。利用Object的GetHashcode方法的返回值,可以在AppDomain中唯一性的标识对象。 下面是.Net中Object代码的实现: [Serializable] publicclassObject { [ReliabilityContract(Consistency.WillNotCorruptState,Cer.MayFail)] publicObject(

相关推荐

推荐阅读