am_kprobe.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. /*
  2. * Copyright (C) 2012 Amlogic, Inc.
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the named License,
  7. * or any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
  17. *
  18. * Author: amlogic SW [platform BJ]
  19. */
  20. #include <linux/kernel.h>
  21. #include <linux/device.h>
  22. #include <linux/module.h>
  23. #include <linux/kallsyms.h>
  24. #include <linux/kprobes.h>
  25. #include <linux/kobject.h>
  26. #include <linux/slab.h>
  27. #include <linux/kdev_t.h>
  28. #include <linux/debugfs.h>
  29. #include <linux/kmod.h>
  30. #include "am_kprobe.h"
  31. static am_kpb_mgr_t am_kpb_mgr;
  32. /* For each probe you need to allocate a kprobe structure */
  33. static ssize_t symbol_show(struct device *dev, struct device_attribute *attr,char *buf)
  34. {
  35. am_kpb_t *am_kpb=dev_get_drvdata(dev);
  36. if(NULL==am_kpb) return 0;
  37. return sprintf(buf,"[symbol name]:%s [addr]:0x%p\r\n",am_kpb->kp.symbol_name,am_kpb->kp.addr);
  38. }
  39. static int register_symbol(am_kpb_t *am_kpb,const char *buf,int count)
  40. {
  41. int ret;
  42. if(NULL!=am_kpb->kp.addr)
  43. {
  44. unregister_kprobe(&am_kpb->kp);
  45. am_kpb->kp.addr=NULL;
  46. am_kpb->kp.flags=0;
  47. }
  48. if(NULL!=buf)
  49. {
  50. memset(am_kpb->symbol,0, KSYM_NAME_LEN);
  51. strncpy(am_kpb->symbol,buf,count-1);
  52. strcpy(am_kpb->symbol,strim(am_kpb->symbol));
  53. am_kpb->kp.symbol_name=(const char*)am_kpb->symbol;
  54. }
  55. if((ret=register_kprobe(&am_kpb->kp))<0)
  56. {
  57. printk("register kprobe failed,%d\n",ret);
  58. am_kpb->kp.addr=NULL;
  59. }
  60. return 0;
  61. }
  62. static ssize_t symbol_store(struct device *dev, struct device_attribute *attr,const char *buf, size_t count)
  63. {
  64. am_kpb_t *am_kpb=dev_get_drvdata(dev);
  65. if(NULL==am_kpb) return 0;
  66. if(NULL==buf) return 0;
  67. register_symbol(am_kpb,buf,count);
  68. return count;
  69. }
  70. static ssize_t offset_store(struct device *dev, struct device_attribute *attr,const char *buf, size_t count)
  71. {
  72. am_kpb_t *am_kpb=dev_get_drvdata(dev);
  73. unsigned offset;
  74. if(NULL==am_kpb) return 0;
  75. offset=simple_strtoul(buf,NULL,0);
  76. printk("[offset]:%d\n",offset);
  77. am_kpb->kp.offset=offset;
  78. if(am_kpb->kp.symbol_name)
  79. register_symbol(am_kpb,NULL,0);
  80. return count;
  81. }
  82. static ssize_t pre_msg_show(struct device *dev, struct device_attribute *attr,char *buf)
  83. {
  84. am_kpb_t *am_kpb=dev_get_drvdata(dev);
  85. if(NULL==am_kpb) return 0;
  86. return sprintf(buf,"pre_msg:%s\r\n",am_kpb->pre_msg);
  87. }
  88. static ssize_t pre_msg_store(struct device *dev, struct device_attribute *attr,const char *buf, size_t count)
  89. {
  90. am_kpb_t *am_kpb=dev_get_drvdata(dev);
  91. if(NULL==am_kpb) return 0;
  92. if(NULL!=am_kpb->pre_msg) kfree(am_kpb->pre_msg);
  93. am_kpb->pre_msg=kzalloc(count-1,GFP_KERNEL);
  94. strncpy(am_kpb->pre_msg,buf,count-1 );
  95. am_kpb->pre_msg=strim(am_kpb->pre_msg);
  96. return count;
  97. }
  98. static ssize_t post_msg_show(struct device *dev, struct device_attribute *attr,char *buf)
  99. {
  100. am_kpb_t *am_kpb=dev_get_drvdata(dev);
  101. if(NULL==am_kpb) return 0;
  102. return sprintf(buf,"post_msg:%s\r\n",am_kpb->post_msg);
  103. }
  104. static ssize_t post_msg_store(struct device *dev, struct device_attribute *attr,const char *buf, size_t count)
  105. {
  106. am_kpb_t *am_kpb=dev_get_drvdata(dev);
  107. if(NULL==am_kpb) return 0;
  108. if(NULL!=am_kpb->post_msg) kfree(am_kpb->post_msg);
  109. am_kpb->post_msg=kzalloc(count-1,GFP_KERNEL);
  110. strncpy(am_kpb->post_msg,buf,count-1 );
  111. am_kpb->post_msg=strim(am_kpb->post_msg);
  112. return count;
  113. }
  114. static ssize_t pre_enable_show(struct device *dev, struct device_attribute *attr,char *buf)
  115. {
  116. am_kpb_t *am_kpb=dev_get_drvdata(dev);
  117. if(NULL==am_kpb) return 0;
  118. return sprintf(buf,"pre_enable:%d\r\n",am_kpb->pre_enable);
  119. }
  120. static ssize_t pre_enable_store(struct device *dev, struct device_attribute *attr,const char *buf, size_t count)
  121. {
  122. am_kpb_t *am_kpb=dev_get_drvdata(dev);
  123. if(NULL==am_kpb) return 0;
  124. sscanf(buf, "%d", &am_kpb->pre_enable);
  125. return count;
  126. }
  127. static ssize_t post_enable_show(struct device *dev, struct device_attribute *attr,char *buf)
  128. {
  129. am_kpb_t *am_kpb=dev_get_drvdata(dev);
  130. if(NULL==am_kpb) return 0;
  131. return sprintf(buf,"post_enable:%d\r\n",am_kpb->post_enable);
  132. }
  133. static ssize_t post_enable_store(struct device *dev, struct device_attribute *attr,const char *buf, size_t count)
  134. {
  135. am_kpb_t *am_kpb=dev_get_drvdata(dev);
  136. if(NULL==am_kpb) return 0;
  137. sscanf(buf, "%d", &am_kpb->post_enable);
  138. return count;
  139. }
  140. static ssize_t hwm_enable_show(struct device *dev, struct device_attribute *attr,char *buf)
  141. {
  142. am_kpb_t *am_kpb=dev_get_drvdata(dev);
  143. if(NULL==am_kpb) return 0;
  144. return sprintf(buf,"pre_enable:%d\r\n",am_kpb->hw_msg_enable);
  145. }
  146. static ssize_t hwm_enable__store(struct device *dev, struct device_attribute *attr,const char *buf, size_t count)
  147. {
  148. am_kpb_t *am_kpb=dev_get_drvdata(dev);
  149. if(NULL==am_kpb) return 0;
  150. sscanf(buf, "%d", &am_kpb->hw_msg_enable);
  151. return count;
  152. }
  153. static ssize_t uhelper_show(struct device *dev, struct device_attribute *attr,char *buf)
  154. {
  155. am_kpb_t *am_kpb=dev_get_drvdata(dev);
  156. if(NULL==am_kpb || NULL==am_kpb->uhelper ) return 0;
  157. return sprintf(buf,"user mode helper:%s\r\n",am_kpb->uhelper );
  158. }
  159. static ssize_t uhelper_store(struct device *dev, struct device_attribute *attr,const char *buf, size_t count)
  160. {
  161. am_kpb_t *am_kpb=dev_get_drvdata(dev);
  162. if(NULL==am_kpb) return 0;
  163. printk("%s---%d\n",buf,count);
  164. if(am_kpb->uhelper) kfree(am_kpb->uhelper);
  165. am_kpb->uhelper=kzalloc(count-1,GFP_KERNEL);
  166. strncpy(am_kpb->uhelper,buf,count-1);
  167. strcpy(am_kpb->uhelper,strim(am_kpb->uhelper));
  168. if(strcmp(am_kpb->uhelper,"")==0 || count==1)
  169. {
  170. am_kpb->uhelper=NULL;
  171. return count;
  172. }
  173. printk("tmpbuffer1:%s",am_kpb->uhelper);
  174. return count;
  175. }
  176. static struct device_attribute kpb_attr[]={
  177. __ATTR(offset, S_IRUGO|S_IWUSR, NULL, offset_store),
  178. __ATTR(pre_msg, S_IRUGO|S_IWUSR, pre_msg_show, pre_msg_store),
  179. __ATTR(post_msg, S_IRUGO|S_IWUSR, post_msg_show, post_msg_store),
  180. __ATTR(symbol, S_IRUGO|S_IWUSR, symbol_show, symbol_store),
  181. __ATTR(pre_enable, S_IRUGO|S_IWUSR, pre_enable_show, pre_enable_store),
  182. __ATTR(post_enable, S_IRUGO|S_IWUSR, post_enable_show, post_enable_store),
  183. __ATTR(hw_msg_enable, S_IRUGO|S_IWUSR, hwm_enable_show, hwm_enable__store),
  184. __ATTR(usr_helper, S_IRUGO|S_IWUSR, uhelper_show, uhelper_store),
  185. __ATTR_NULL
  186. };
  187. static ssize_t max_pb_num_show(struct class *class, struct class_attribute *attr,char *buf)
  188. {
  189. return sprintf(buf,"probe num:%d\r\n", am_kpb_mgr.pb_num);
  190. }
  191. static ssize_t max_pb_num_store(struct class *class, struct class_attribute *attr,const char *buf, size_t count)
  192. {
  193. int number,i;
  194. sscanf(buf, "%d", &number);
  195. if(MAX_PB_NUM < number)
  196. {
  197. printk("cant create breakpoints more than %d\n",MAX_PB_NUM);
  198. return count;
  199. }
  200. /*create new probe point*/
  201. if(number==am_kpb_mgr.pb_num) return count;
  202. for(i=am_kpb_mgr.pb_num+1;i<=number;i++) //add extra new ones
  203. {
  204. am_kpb_mgr.pb_points[i]=init_one_pb_point(i,am_kpb_mgr.pb_points[i]);
  205. }
  206. for(i=am_kpb_mgr.pb_num;i>number;i--) //delete unused ones
  207. {
  208. deinit_one_pb_point(i,am_kpb_mgr.pb_points[i]);
  209. am_kpb_mgr.pb_points[i]=NULL;
  210. }
  211. am_kpb_mgr.pb_num=number;
  212. return count;
  213. }
  214. static ssize_t addr2sym_store(struct class *class, struct class_attribute *attr,const char *buf, size_t count)
  215. {
  216. ulong addr;
  217. char symbol[KSYM_NAME_LEN];
  218. addr=simple_strtoul(buf,NULL,0);
  219. sprint_symbol(symbol,addr);
  220. printk("[addr]:0x%lx --[symbol]:%s\n",addr,symbol);
  221. return count;
  222. }
  223. static struct class_attribute kpb_mgr_attr[]={
  224. __ATTR(max_pb_num, S_IRUGO|S_IWUSR,max_pb_num_show,max_pb_num_store),
  225. __ATTR(addr2sym, S_IRUGO|S_IWUSR, NULL, addr2sym_store),
  226. };
  227. static inline void dump_message(am_kpb_t *am_kpb,struct pt_regs *regs)
  228. {
  229. struct kprobe *p=&am_kpb->kp;
  230. if(0==am_kpb->hw_msg_enable) return ;
  231. printk("dump cpu regs:\n");
  232. printk("pc: 0x%lx\t lr:0x%lx\n",regs->ARM_pc,regs->ARM_lr);
  233. printk("sp: 0x%lx\t ip:0x%lx\n",regs->ARM_sp,regs->ARM_ip);
  234. printk("fp:0x%lx\t r10:0x%lx\n",regs->ARM_fp,regs->ARM_r10);
  235. printk("r9:0x%lx\t r8:0x%lx\n",regs->ARM_r9,regs->ARM_r8);
  236. printk("r7:0x%lx\t r6:0x%lx\n",regs->ARM_r7,regs->ARM_r6);
  237. printk("r5:0x%lx\t r4:0x%lx\n",regs->ARM_r5,regs->ARM_r4);
  238. printk("r3:0x%lx\t r2:0x%lx\n",regs->ARM_r3,regs->ARM_r2);
  239. printk("r1:0x%lx\t r0:0x%lx\n",regs->ARM_r1,regs->ARM_r0);
  240. printk("dump kprobe msg:\n");
  241. printk("addr:0x%p \t symbol:%s\n",p->addr,p->symbol_name);
  242. printk("saved op code(rpl by bp):0x%x\n",p->opcode);
  243. printk("origin instr opcode:0x%p handler:0x%p\n",p->ainsn.insn,p->ainsn.insn_handler);
  244. }
  245. static void call_uhelper(am_kpb_t *am_kpb,char pos)
  246. {
  247. char *argv [3];
  248. int ret;
  249. struct kobj_uevent_env *env;
  250. const char *subsystem;
  251. const char *devpath;
  252. subsystem = am_kpb->dev->kobj.name;
  253. //kobject_uevent(&am_kpb->dev->kobj, KOBJ_ADD);
  254. if(NULL== am_kpb->uhelper) return ;
  255. argv [0] = am_kpb->uhelper;
  256. argv [1] = (char *)subsystem;
  257. argv [2] = NULL;
  258. env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);
  259. //add_uevent_var(env, "ACTION=%s","add");
  260. add_uevent_var(env, "PREV_POST=%s", (pos==POS_POST)?"post":"prev");
  261. add_uevent_var(env, "SUBSYSTEM=%s", subsystem);
  262. devpath = kobject_get_path(&am_kpb->dev->kobj, GFP_KERNEL);
  263. add_uevent_var(env, "DEVPATH=%s", devpath);
  264. add_uevent_var(env, "SUBSYSTEM=%s", subsystem);
  265. ret = add_uevent_var(env, "HOME=/");
  266. if (ret)
  267. goto exit_helper;
  268. ret= add_uevent_var(env,
  269. "PATH=/sbin:/bin:/usr/sbin:/usr/bin");
  270. if (ret)
  271. goto exit_helper;
  272. ret = call_usermodehelper(argv[0], argv,
  273. env->envp, UMH_WAIT_EXEC);
  274. exit_helper:
  275. kfree(env);
  276. return ;
  277. }
  278. /* kprobe pre_handler: called just before the probed instruction is executed */
  279. static int handler_pre(struct kprobe *p, struct pt_regs *regs)
  280. {
  281. am_kpb_t *am_kpb=kprobe_to_am_kpb(p);
  282. if(NULL==am_kpb) return 0;
  283. if(0==am_kpb->pre_enable) return 0;
  284. if(am_kpb->pre_msg)
  285. printk("%s",am_kpb->pre_msg);
  286. dump_message(am_kpb,regs);
  287. call_uhelper(am_kpb,POS_PRE);
  288. return 0;
  289. }
  290. /* kprobe post_handler: called after the probed instruction is executed */
  291. static void handler_post(struct kprobe *p, struct pt_regs *regs,
  292. unsigned long flags)
  293. {
  294. am_kpb_t *am_kpb=kprobe_to_am_kpb(p);
  295. if(NULL==am_kpb) return ;
  296. if(0==am_kpb->post_enable) return ;
  297. if(am_kpb->post_msg)
  298. printk("%s",am_kpb->post_msg);
  299. dump_message(am_kpb,regs);
  300. call_uhelper(am_kpb,POS_POST);
  301. return ;
  302. }
  303. /*
  304. * fault_handler: this is called if an exception is generated for any
  305. * instruction within the pre- or post-handler, or when Kprobes
  306. * single-steps the probed instruction.
  307. */
  308. static int handler_fault(struct kprobe *p, struct pt_regs *regs, int trapnr)
  309. {
  310. am_kpb_t *am_kpb=kprobe_to_am_kpb(p);
  311. int origin_hw_msg_enable=am_kpb->hw_msg_enable;
  312. printk(KERN_INFO "fault_handler: p->addr = 0x%p, trap #%dn",
  313. p->addr, trapnr);
  314. /*enable hw messge enable to see it*/
  315. am_kpb->hw_msg_enable=1;
  316. dump_message(am_kpb,regs);
  317. am_kpb->hw_msg_enable=origin_hw_msg_enable;
  318. /* Return 0 because we don't handle the fault. */
  319. return 0;
  320. }
  321. static int deinit_one_pb_point(int index,am_kpb_t *am_kpb)
  322. {
  323. int i ;
  324. const dev_t dev_id = MKDEV(MAJOR(am_kpb_mgr.kbp_devid), index);
  325. if(NULL==am_kpb) return -1;
  326. for(i=0;NULL!=kpb_attr[i].attr.name;i++)
  327. {
  328. device_remove_file(am_kpb->dev,&kpb_attr[i]);
  329. }
  330. device_destroy(am_kpb_mgr.base_class, dev_id);
  331. kfree(am_kpb);
  332. return 0;
  333. }
  334. static am_kpb_t* init_one_pb_point(int index,am_kpb_t *am_kpb)
  335. {
  336. am_kpb_t* p_am_kpb=NULL;
  337. int i=0;
  338. struct kobject *kobj;
  339. const dev_t dev_id = MKDEV(MAJOR(am_kpb_mgr.kbp_devid), index);
  340. if(am_kpb && NULL!=am_kpb->dev) return NULL;
  341. if(am_kpb) kfree(am_kpb);
  342. p_am_kpb=(am_kpb_t*)kmalloc(sizeof(am_kpb_t),GFP_KERNEL);
  343. if(NULL==p_am_kpb)
  344. {
  345. printk("no memory for new kprobe obj");
  346. return NULL;
  347. }
  348. p_am_kpb->kp.pre_handler = handler_pre;
  349. p_am_kpb->kp.post_handler = handler_post;
  350. p_am_kpb->kp.fault_handler = handler_fault;
  351. p_am_kpb->kp.addr=NULL;
  352. p_am_kpb->pre_enable=0;
  353. p_am_kpb->post_enable=0;
  354. p_am_kpb->hw_msg_enable=0;
  355. p_am_kpb->pre_msg=NULL;
  356. p_am_kpb->post_msg=NULL;
  357. p_am_kpb->index=index;
  358. kobj =&p_am_kpb->kobj ;
  359. if(NULL==kobj)
  360. {
  361. printk("no memory for create probe object\n");
  362. goto exit;
  363. }
  364. p_am_kpb->dev = device_create(am_kpb_mgr.base_class, NULL, dev_id, NULL, "breakpoint%d",index); //kernel>=2.6.27
  365. for(i=0;NULL!=kpb_attr[i].attr.name;i++)
  366. {
  367. if(0>device_create_file(p_am_kpb->dev,&kpb_attr[i]))
  368. {
  369. printk("create file attr %s failed\n",kpb_attr[i].attr.name);
  370. }
  371. }
  372. dev_set_drvdata(p_am_kpb->dev, p_am_kpb);
  373. exit:
  374. return p_am_kpb;
  375. }
  376. static int __init kprobe_init(void)
  377. {
  378. int i;
  379. struct dentry *fd;
  380. printk("insert am kprobe module ok\n");
  381. /*create kprobe class*/
  382. i=alloc_chrdev_region(&am_kpb_mgr.kbp_devid, 0,1, KPB_CLASS_NAME);
  383. printk("dev_t for aml_kprobe:[%d:%d]\n",MAJOR(am_kpb_mgr.kbp_devid),MINOR(am_kpb_mgr.kbp_devid));
  384. if(i<0)
  385. {
  386. printk("can't alloc char device region for aml_kprobe\n");
  387. return -1;
  388. }
  389. am_kpb_mgr.base_class=class_create(THIS_MODULE,KPB_CLASS_NAME);
  390. if(NULL==am_kpb_mgr.base_class)
  391. {
  392. printk("can not create kpb base class \n");
  393. return -1;
  394. }
  395. am_kpb_mgr.pb_num=0;
  396. for(i=0;i<ARRAY_SIZE(kpb_mgr_attr);i++)
  397. {
  398. if ( class_create_file(am_kpb_mgr.base_class,&kpb_mgr_attr[i]))
  399. {
  400. printk("create kpb attribute %s fail\r\n",kpb_mgr_attr[i].attr.name);
  401. }
  402. }
  403. /*create debugfs interface here*/
  404. am_kpb_mgr.dbg_dir=debugfs_create_dir(KPB_CLASS_NAME,NULL);
  405. fd = debugfs_create_u32("max_pb_num", S_IRUGO, am_kpb_mgr.dbg_dir,
  406. (u32 *)&am_kpb_mgr.pb_num);
  407. if(0 > fd )
  408. {
  409. printk("cant create debufs file max_pb_num\n ");
  410. }
  411. return 0;
  412. }
  413. static void __exit kprobe_exit(void)
  414. {
  415. int i;
  416. printk(KERN_INFO "am kprobe exit\n");
  417. debugfs_remove_recursive(am_kpb_mgr.dbg_dir);
  418. for(i=1;i <= am_kpb_mgr.pb_num;i++) //delete unused ones
  419. {
  420. deinit_one_pb_point(i,am_kpb_mgr.pb_points[i]);
  421. }
  422. if(NULL==am_kpb_mgr.base_class) return ;
  423. for(i=0;i<ARRAY_SIZE(kpb_mgr_attr);i++)
  424. {
  425. class_remove_file(am_kpb_mgr.base_class,&kpb_mgr_attr[i]) ;
  426. }
  427. class_destroy(am_kpb_mgr.base_class);
  428. unregister_chrdev_region(am_kpb_mgr.kbp_devid,1);
  429. }
  430. module_init(kprobe_init)
  431. module_exit(kprobe_exit)
  432. MODULE_LICENSE("GPL");