emacs+cscope之call function失败解决分析(六十二)

微生旻
2023-12-01
1.cscope查看函数定义时报错
报错如下:
Database directory: android12
Lseek failed: Invalid argument
Search complete.  Search time = 4.11 seconds.
2.分析过程

通过对cscope编译debug,最终发现传入一个特别大的索引数据,导致lseek()把它当成无效参数。

log如下:

find.c, dbseek(), line = 1250, offset = 0, BUFSIZ = 8192, blocknumber = -1

find.c, dbseek(), line = 1261, offset = 0, BUFSIZ = 8192, blocknumber = 0

find.c, dbseek(), offset = 3472328295956396737, BUFSIZ = 8192, blocknumber = 0

find.c, dbseek(),  offset = 3472328295956396737, BUFSIZ = 8192, blocknumber = 0, n = 423868200189989

Lseek failed: Invalid argument
  • 从上边看出lseek()传入的offset为:3472328295956396737,初步算下它到底有多大?

3472328295956396737 = 3472328TB,竟然这么大的数据。

  • 开始还以为是lseek()用的32位api导致的,最后即使换成lseek64()的64位api也没啥用,由于主机使4T的硬盘,发现lseek64()最多可以访问8TB内存,如果传入16TB直接报无效参数。

  • 于是写了一个例子验证下

  1. 验证sample

//1.lseek64()
//#define _GNU_SOURCE /* for O_DIRECT */

//Or: 2.lseek64()
#define __USE_FILE_OFFSET64
#define __USE_LARGEFILE64
#define _LARGEFILE64_SOURCE

#include <iostream>
#include <unistd.h>
#include <dirent.h>
#include <stdlib.h>
#include<typeinfo>
#include<climits>
#include <fcntl.h>
#include <sys/types.h>
using namespace std;

int main(int argc,char*argv[]){

  //2.lseek 64 bit usage
  //long count = 3472328295956396737 = 3472328TB
  //4294967295 //4G
  //9223372036854775807 = 2^63 -1 (long) : 9223372TB

  long count = (1L << 44) - 1;
  printf("count = %ld\n",count);
  
  //printf("sizeof(off64_t) = %ld\n",sizeof(off64_t));
  // printf("type(off64_t) = %s\n",typeid(off64_t).name()); //off64_t : long
  // printf("type(count) = %s\n",typeid(count).name()); //count: long
  // printf("type(LONG_MAX) = %s\n",typeid(LONG_MAX).name());
  // printf("LONG_MAX = %ld\n",LONG_MAX);
  
  //open
  int fd = open(argv[1], O_LARGEFILE | O_RDWR, 0666);
  //if(lseek64(STDIN_FILENO, (off64_t)count, 0) == -1)

  //lseek64
  long size = lseek64(fd, (long)count, 0);
  printf("size = %ld\n",size);
  if(size == -1)
    perror("Lseek failed");
  else
    printf("seek OK\n");

  return 0;
}
3.猜测
  • 最终猜测是cscope.out索引导致的问题,可能超过200GB的代码使用cscope可能就有问题;但是单独用小于200GB的小文件倒是没问题,这其实也算是一种解决办法。

  • 猜测是cscope的bug导致的,因为cscope自从2018年更新到v15.9以后,再也没更新了。

4.结论与解决

竟然是参数不对导致的,如下优化修改可以解决大工程源码问题。

优化修改/usr/local/bin/cscope-indexer:

<1>.忽略索引prebuilts和out目录

-  #find $DIR \( -type f -o -type l \)
+  find $DIR ! -path "./out/*.[c]" ! -path "./out/*x86_64*/*"  ! -path "./prebuilts/*" \( -type f -o -type l \)

<2>.修改需要索引的文件

-  egrep -i '\.([chly](xx|pp)*|cc|hh|java|cpp|Makefile|mk|aidl|xml|sh|te|rc|bp|dtsi|hal)$' | \
+  egrep -i '\.([ch](xx|pp)*|java|aidl|hal)$' | \

Or
//h、cpp、c
+  egrep -i '\.(h|cpp|c|java|aidl|hal)$' | \

Or 
//c、cpp、cxx、cc、h、hc、hxx、hpp
+  egrep -i '\.([ch](c|xx|pp)*|java|aidl|hal)$' | \

注意:同时索引cpp和cc或c和cc导致冲突,无法找到调用函数,这时可以不索引.cc结尾的文件。

如果cscope无法找到该函数可以使用:cscope-find-egrep-pattern命令,不过时间在20s以内。

<3>.修改索引命令(可选)

-  cscope -Rqbk -i  $LIST_FILE -f $DATABASE_FILE
+  cscope -RqbkuC -i  $LIST_FILE -f $DATABASE_FILE

此处不修改也没问题。

感受cscope的强大吧!

 类似资料: