1. <wbr id="cnjas"><legend id="cnjas"></legend></wbr>

          Linux培訓
          達內IT學院

          400-111-8989

          Linux虛擬內存地址轉化成物理內存地址

          • 發布:Linux培訓
          • 來源:Linux教程
          • 時間:2017-07-25 15:38

          背景

          現代手機這種SOC(system on chip),因為功耗、Modem等功能soc上集成了很多core,他們還可以是獨立的系統在運轉。

          比如ADSP簡介ADSP(Application Digital Signal Processing)就是高通的Hexagon DSP ,就是獨立運轉的一個core+system。這樣做不僅可以使用soc上的專用核處理專業的事情,比如上面說的ADSP就可以處理音頻解碼,當然它的DSP特性還可以處理sensor融合算法,比起通用處理器(cortex a72 a53 a17 a9 a8這些核)處理效率更高,更省電。

          當然出于成本因素我們不會為它單獨焊上一個內存顆粒,它共享了主存的一部分,比如從地址0xc0000000 - 0xc0100000 1MB的空間,此時內核(Linux運行在通用處理器上)將不再觸碰這塊內存。

          但是多核共享同一個地址空間也有個弊端,就是如果程序有問題(野指針,數組越界)可能會寫別的core管理的內存空間,這樣給我們帶來的問題就是程序的值莫名其妙的被改變了。我們為了排查這種問題,才考慮把應用程序的虛擬地址轉化為物理地址,進行print debug以便于統一分析。

          實現

          kernel 在2.6.25的時候加入了這樣一個功能/proc/self/pagemap 也就是在每個進程的/proc里面都有一個pagemap通過讀取里面的內容就可以算出當前虛擬地址對應的物理頁,然后加入page_offset就可以知道當前虛擬地址對應的物理地址。

          pagemap需要你的應用有root權限才能使用。

          #include <errno.h>

          #include <stdio.h>

          #include <sys/stat.h>

          #include <string.h>

          #include <fcntl.h>

          #include <stdlib.h>

          #include <stdint.h>

          #include <sys/types.h>

          #include <sys/stat.h>

          #include <fcntl.h>

          #include <unistd.h>

          #include <sys/mman.h>

          // 參考

          // https://www.kernel.org/doc/Documentation/vm/pagemap.txt

          #define page_map_file "/proc/self/pagemap"

          #define PFN_MASK ((((uint64_t)1)<<55)-1)

          #define PFN_PRESENT_FLAG (((uint64_t)1)<<63)

          int mem_addr_vir2phy(unsigned long vir, unsigned long *phy)

          {

          int fd;

          int page_size=getpagesize();

          unsigned long vir_page_idx = vir/page_size;

          unsigned long pfn_item_offset = vir_page_idx*sizeof(uint64_t);

          uint64_t pfn_item;

          fd = open(page_map_file, O_RDONLY);

          if (fd<0)

          {

          fprintf(stderr, "open %s failed", page_map_file);

          return -1;

          }

          if ((off_t)-1 == lseek(fd, pfn_item_offset, SEEK_SET))

          {

          fprintf(stderr, "lseek %s failed", page_map_file);

          return -1;

          }

          if (sizeof(uint64_t) != read(fd, &pfn_item, sizeof(uint64_t)))

          {

          fprintf(stderr, "read %s failed", page_map_file);

          return -1;

          }

          if (0==(pfn_item & PFN_PRESENT_FLAG))

          {

          fprintf(stderr, "page is not present");

          return -1;

          }

          *phy = (pfn_item & PFN_MASK)*page_size + vir % page_size;

          return 0;

          }

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

          unsigned long a = 0xffbbccaa;

          unsigned long vir = reinterpret_cast<unsigned long>(&a);

          unsigned long phy = 0;

          fprintf(stderr, "sizeof(unsigned long):%lu, sizeof(unsigned long*):%lu\n", sizeof(unsigned long), sizeof(unsigned long*));

          mem_addr_vir2phy(vir, &phy);

          fprintf(stderr, "1 vir:0x%lx, phy: 0x%lx getchar to continue\n", vir, phy);

          getchar();

          a = 0x11111111;

          fprintf(stderr, "2 vir:0x%lx, phy: 0x%lx getchar to continue\n", vir, phy);

          getchar();

          fprintf(stderr, "3 vir:0x%lx, phy: 0x%lx a:0x%lx\n", vir, phy, a);

          }

          如何驗證

          你需要開啟kernel如下模塊

          CONFIG_DEVMEM=y

          關閉如下模塊

          CONFIG_STRICT_DEVMEM=n

          一般的Android 都有/system/bin/r(源碼在system/core/toolbox/r.c)這個命令,這個命令類似devmem之類的嵌入式工具,通過/dev/mem(物理內存)mmap來讀取物理內存的值,當然你也可以修改該地址的值

          上面的例子他們通過getchar() 阻止程序的運行,以便你有足夠的時間來敲/system/bin/r命令和參數

          命令用法,上面的例子我們取了一個棧上變量的虛擬地址,轉換成物理地址。然后你就可以通過/system/bin/r來讀取和修改這個地址的值了。

          讀取0x9a6f0b20地址的值

          adb shell /system/bin/r 0x9a6f0b20

          修改0x9a6f0b20地址的值為0xffbbccaa

          adb shell /system/bin/r 0x9a6f0b20 0xffbbccaa

          源碼可以直接git clone git@github.com:green130181/kernel-study.git

          工程里的 pagemap直接拷貝到aosp的任意目錄

          然后aosp的根目錄執行

          source build/envsetup.sh

          lunch "your select"

          cd pagemap dir

          mm

          之后adb push 到你的機器,即可開始驗證。

          當然還有很多先進的比如ramdump Trace32來實現內存地址查看,不過上面的對于一個應用來講足夠輕量級,夠用就好!

          預約申請免費試聽課

          填寫下面表單即可預約申請免費試聽!怕錢不夠?可就業掙錢后再付學費! 怕學不會?助教全程陪讀,隨時解惑!擔心就業?一地學習,可全國推薦就業!

          上一篇:Linux的一些腦洞操作 你值得擁有!
          下一篇:這些技能讓你玩轉Linux!
          • 掃碼領取資料

            回復關鍵字:視頻資料

            免費領取 達內課程視頻學習資料

          • 視頻學習QQ群

            添加QQ群:1143617948

            免費領取達內課程視頻學習資料

          Copyright ? 2021 Tedu.cn All Rights Reserved 京ICP備08000853號-56 京公網安備 11010802029508號 達內時代科技集團有限公司 版權所有

          選擇城市和中心
          黑龍江省

          吉林省

          河北省

          湖南省

          貴州省

          云南省

          廣西省

          海南省

          欧美做爰视频免费播放_做暖全过程免费的视频_性爱免费视频 百度 好搜 搜狗
          <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <文本链> <文本链> <文本链> <文本链> <文本链> <文本链>